org.alljoyn.bus.samples.simpleclient.DevicesActivity.java Source code

Java tutorial

Introduction

Here is the source code for org.alljoyn.bus.samples.simpleclient.DevicesActivity.java

Source

/*
 * Copyright 2010-2011, Qualcomm Innovation Center, Inc.
 * 
 *    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 org.alljoyn.bus.samples.simpleclient;

import android.app.ProgressDialog;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.support.v4.app.Fragment;
import android.support.v4.app.FragmentActivity;
import android.support.v4.app.FragmentManager;
import android.support.v4.app.FragmentTransaction;
import android.util.Log;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import org.alljoyn.bus.BusAttachment;
import org.alljoyn.bus.BusException;
import org.alljoyn.bus.BusListener;
import org.alljoyn.bus.Mutable;
import org.alljoyn.bus.ProxyBusObject;
import org.alljoyn.bus.SessionListener;
import org.alljoyn.bus.SessionOpts;
import org.alljoyn.bus.Status;

import java.util.ArrayList;

public class DevicesActivity extends FragmentActivity
        implements DeviceListFragment.OnDeviceSelectedListener, DeviceDetailsFragment.OnButtonClickedListener {
    /* Load the native alljoyn_java library. */
    static {
        System.loadLibrary("alljoyn_java");
    }

    private static final int MESSAGE_PING = 1;
    private static final int MESSAGE_PING_REPLY = 2;
    private static final int MESSAGE_POST_TOAST = 3;
    private static final int MESSAGE_START_PROGRESS_DIALOG = 4;
    private static final int MESSAGE_STOP_PROGRESS_DIALOG = 5;
    private static final int MESSAGE_ADD_FOUND_DEVICE = 6;
    private static final int MESSAGE_REMOVE_FOUND_DEVICE = 7;
    private static final int MESSAGE_UPDATE_DETAILSFRAGMENT_UI = 8;

    //TODO
    // should make transport a variable
    private short DEVICE_TRANSPORT;
    private static final String SERVICE_NAME = "org.alljoyn.bus.samples.simple";
    private static String mDeviceType;
    private static String mDeviceName;

    private static final String TAG = "SimpleDevicesClient";

    private ArrayAdapter<String> mListViewArrayAdapter;
    private ListView mListView;
    private Menu menu;

    private ArrayList<Service> serviceArrayList = new ArrayList<Service>();

    private Bundle mBundle;
    private Context mContext;

    // Git is cool
    // this is definitely cool
    // so now what?

    //

    /* Handler used to make calls to AllJoyn methods. See onCreate(). */
    private BusHandler mBusHandler;

    private ProgressDialog mDialog;

    //private Fragment mDeviceListFragment;

    private DeviceListFragment mDeviceListFragment;
    private DeviceDetailsFragment mDeviceDetailsFragment;

    //    /**
    //     * Called from the AllJoyn Service when it gets a FoundAdvertisedName.  We
    //     * know by construction that the advertised name will correspond to an chat
    //     * channel.  Note that the channel here is the complete well-known name of
    //     * the bus attachment advertising the channel.  In most other places it is
    //     * simply the channel name, which is the final segment of the well-known
    //     * name.
    //     */
    //    public synchronized void addFoundDevice(Service foundService) {
    //        Log.i(TAG, "addFoundDevice(" + foundService.getWellKnownName() + ")");
    //        Message msg = mHandler.obtainMessage(MESSAGE_ADD_FOUND_DEVICE);
    //        msg.obj = foundService.getWellKnownName();
    //        msg.arg1 = foundService.getTransport();
    //        mHandler.sendMessage(msg);
    //    }

    /**
     * Called from the AllJoyn Service when it gets a FoundAdvertisedName.  We
     * know by construction that the advertised name will correspond to an chat
     * channel.  Note that the channel here is the complete well-known name of
     * the bus attachment advertising the channel.  In most other places it is
     * simply the channel name, which is the final segment of the well-known
     * name.
     */
    public synchronized void addFoundDevice(Message deviceInfo) {
        mHandler.sendMessage(deviceInfo);
    }

    //
    //    /**
    //     * Called from the AllJoyn Service when it gets a LostAdvertisedName.  We
    //     * know by construction that the advertised name will correspond to an chat
    //     * channel.
    //     */
    //    public synchronized void removeFoundDevice(Service lostService) {
    //        Log.i(TAG, "removeFoundDevice(" + lostService.getWellKnownName() + ")");
    //        Message msg = mHandler.obtainMessage(MESSAGE_REMOVE_FOUND_DEVICE);
    //        msg.obj = lostService.getWellKnownName();
    //        msg.arg1 = lostService.getTransport();
    //        mHandler.sendMessage(msg);
    //    }

    /**
     * Called from the AllJoyn Service when it gets a LostAdvertisedName.  We
     * know by construction that the advertised name will correspond to an chat
     * channel.
     */
    public synchronized void removeFoundDevice(Message deviceInfo) {
        mHandler.sendMessage(deviceInfo);
    }

    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {

            int deviceNum;
            String deviceName;
            switch (msg.what) {
            case MESSAGE_PING:
                String ping = (String) msg.obj;
                mListViewArrayAdapter.add("Ping:  " + ping);
                break;
            case MESSAGE_PING_REPLY:
                String ret = (String) msg.obj;
                mListViewArrayAdapter.add("Reply:  " + ret);

                break;
            case MESSAGE_POST_TOAST:
                Toast.makeText(getApplicationContext(), (String) msg.obj, Toast.LENGTH_LONG).show();
                break;
            case MESSAGE_START_PROGRESS_DIALOG:
                mDialog = ProgressDialog.show(DevicesActivity.this, "", "Finding Simple Service.\nPlease wait...",
                        true, true);
                break;
            case MESSAGE_STOP_PROGRESS_DIALOG:
                mDialog.dismiss();
                break;
            case MESSAGE_ADD_FOUND_DEVICE:
                deviceName = msg.obj.toString();
                Log.i("Device Name", deviceName); // "com.flybits.devices.coffeemaker.My_Coffee_Maker"
                deviceName = deviceName.replace(SERVICE_NAME + ".", "").replace("_", " "); // "coffeemaker.My Coffee Maker"

                mDeviceListFragment.addFoundDevice(deviceName);
                if (mDialog.isShowing()) {
                    mHandler.sendEmptyMessage(MESSAGE_STOP_PROGRESS_DIALOG);
                }

                break;
            case MESSAGE_REMOVE_FOUND_DEVICE:
                deviceName = msg.obj.toString(); // "com.flybits.devices.coffeemaker.My_Coffee_Maker"
                deviceName = deviceName.replace(SERVICE_NAME + ".", "").replace("_", " "); // "coffeemaker.My Coffee Maker"

                mDeviceListFragment.removeFoundDevice(deviceName);
                deviceNum = mDeviceListFragment.getDeviceArraySize();
                if (deviceNum <= 0 && !mDialog.isShowing()) {
                    mHandler.sendEmptyMessage(MESSAGE_START_PROGRESS_DIALOG);
                }
                break;
            case MESSAGE_UPDATE_DETAILSFRAGMENT_UI:

                TextView textView = (TextView) findViewById(R.id.deviceNameTextView);
                textView.setText(mBundle.getString("Name"));

                break;
            default:
                break;
            }
        }
    };

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_devices);
        mContext = this;

        //        mEditText = (EditText) findViewById(R.id.EditText);
        //        mEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
        //                public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
        //                    if (actionId == EditorInfo.IME_NULL
        //                        && event.getAction() == KeyEvent.ACTION_UP) {
        //                        /* Call the remote object's Ping method. */
        //                        Message msg = mBusHandler.obtainMessage(BusHandler.PING, 
        //                                                                view.getText().toString());
        //                        mBusHandler.sendMessage(msg);
        //                    }
        //                    return true;
        //                }
        //            });

        //Master data list Fragment

        String fullName = SERVICE_NAME + ".coffeemaker.Beagle_Bone";
        String[] tokens = fullName.split("[.]");
        for (String token : tokens) {
            Log.i("token:", token);
        }

        mDeviceListFragment = new DeviceListFragment();
        FragmentManager fragmentManager = getSupportFragmentManager();
        FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
        fragmentTransaction.add(R.id.myFragmentContainer, mDeviceListFragment, "DeviceListFragment");
        fragmentTransaction.commit();

        /* Make all AllJoyn calls through a separate handler thread to prevent blocking the UI. */
        HandlerThread busThread = new HandlerThread("BusHandler");
        busThread.start();
        mBusHandler = new BusHandler(busThread.getLooper());

        /* Connect to an AllJoyn object. */
        mBusHandler.sendEmptyMessage(BusHandler.CONNECT);
        mHandler.sendEmptyMessage(MESSAGE_START_PROGRESS_DIALOG);
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.mainmenu, menu);
        this.menu = menu;
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle item selection
        switch (item.getItemId()) {
        case R.id.quit:
            finish();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();

        /* Disconnect to prevent resource leaks. */
        mBusHandler.sendEmptyMessage(BusHandler.DISCONNECT);
    }

    @Override
    public void onDeviceSelected(String deviceName) {
        // Store the created fragment into a variable
        if (mDeviceDetailsFragment == null) {
            FragmentManager fragmentManager = getSupportFragmentManager();
            mDeviceDetailsFragment = (DeviceDetailsFragment) fragmentManager
                    .findFragmentByTag("DeviceDetailsFragment");
        }
        Log.d("Device selected:", deviceName); // coffeemaker.My Coffee Maker
        //TODO
        // What happens when 2 services have the same name?
        Message msg = mBusHandler.obtainMessage(mBusHandler.JOIN_SESSION);
        msg.arg1 = DEVICE_TRANSPORT;
        String fullAdvertisedName = SERVICE_NAME + "." + deviceName.replace(" ", "_"); // com.flybits.devices.coffeemaker.My_Coffee_Maker
        msg.obj = fullAdvertisedName;
        mBusHandler.sendMessage(msg);
    }

    @Override
    public void onButtonClicked() {
        mBusHandler.sendEmptyMessage(BusHandler.GET_DEVICE_NAME);
    }

    /* This class will handle all AllJoyn calls. See onCreate(). */
    class BusHandler extends Handler {
        /*
         * Name used as the well-known name and the advertised name of the service this client is
         * interested in.  This name must be a unique name both to the bus and to the network as a
         * whole.
         *
         * The name uses reverse URL style of naming, and matches the name used by the service.
         */
        private static final String SERVICE_NAME = "org.alljoyn.bus.samples.simple";
        private static final short CONTACT_PORT = 42;

        private BusAttachment mBus;
        private ProxyBusObject mProxyObj;
        private SimpleInterface mSimpleInterface;
        private CoffeeMakerInterface mCoffeeMakerInterface;
        private ThermostatInterface mThermostatInterface;

        private int mSessionId;
        private boolean mIsInASession;
        private boolean mIsConnected;
        private boolean mIsStoppingDiscovery;

        /* These are the messages sent to the BusHandler from the UI. */
        public static final int CONNECT = 1;
        public static final int JOIN_SESSION = 2;
        public static final int DISCONNECT = 3;
        public static final int PING = 4;
        public static final int GET_DEVICE_NAME = 5;

        public BusHandler(Looper looper) {
            super(looper);

            mIsInASession = false;
            mIsConnected = false;
            mIsStoppingDiscovery = false;
        }

        private void interfaceSelector(String deviceType, String WellKnownName, int sessionIdvalue,
                boolean connect) {
            if (connect) {
                if (deviceType.contentEquals("coffeemaker")) {
                    Log.d("interface", "coffeemaker");
                    mProxyObj = mBus.getProxyBusObject(WellKnownName, "/coffeemaker", sessionIdvalue,
                            new Class<?>[] { CoffeeMakerInterface.class });

                    /* We make calls to the methods of the AllJoyn object through one of its interfaces. */
                    mCoffeeMakerInterface = mProxyObj.getInterface(CoffeeMakerInterface.class);
                } else if (deviceType.contentEquals("thermostat")) {
                    Log.d("interface", "thermostat");
                    mProxyObj = mBus.getProxyBusObject(WellKnownName, "/thermo", sessionIdvalue,
                            new Class<?>[] { ThermostatInterface.class });

                    /* We make calls to the methods of the AllJoyn object through one of its interfaces. */
                    mThermostatInterface = mProxyObj.getInterface(ThermostatInterface.class);
                } else {
                    Log.d("interface", "simple");
                    mProxyObj = mBus.getProxyBusObject(WellKnownName, "/simple", sessionIdvalue,
                            new Class<?>[] { SimpleInterface.class });

                    /* We make calls to the methods of the AllJoyn object through one of its interfaces. */
                    mSimpleInterface = mProxyObj.getInterface(SimpleInterface.class);
                }
            } else {
                //TODO
                // make a list of interfaces
                mProxyObj = null;
                mCoffeeMakerInterface = null;
                mThermostatInterface = null;
                mSimpleInterface = null;
            }
        }

        @Override
        public void handleMessage(Message msg) {
            switch (msg.what) {
            /* Connect to a remote instance of an object implementing the SimpleInterface. */
            case CONNECT: {
                org.alljoyn.bus.alljoyn.DaemonInit.PrepareDaemon(getApplicationContext());
                /*
                 * All communication through AllJoyn begins with a BusAttachment.
                 *
                 * A BusAttachment needs a name. The actual name is unimportant except for internal
                 * security. As a default we use the class name as the name.
                 *
                 * By default AllJoyn does not allow communication between devices (i.e. bus to bus
                 * communication). The second argument must be set to Receive to allow communication
                 * between devices.
                 */
                mBus = new BusAttachment(getPackageName(), BusAttachment.RemoteMessage.Receive);

                /*
                 * Create a bus listener class
                 */
                mBus.registerBusListener(new BusListener() {
                    @Override
                    public void lostAdvertisedName(String name, short transport, String namePrefix) {
                        logInfo(String.format("MyBusListener.lostAdvertisedName(%s, 0x%04x, %s)", name, transport,
                                namePrefix));

                        //                        Service service = new Service(name);
                        //                        service.setTransport(transport);
                        //                        service.setWellKnownNamePrefix(namePrefix);
                        //                        serviceArrayList.remove(service);
                        //
                        //                        for (Service service1: serviceArrayList) {
                        //                            Log.d("serviceArrayList",service1.getWellKnownName());
                        //                        }

                        Message deviceInfo = obtainMessage(MESSAGE_REMOVE_FOUND_DEVICE);
                        deviceInfo.arg1 = transport;
                        DEVICE_TRANSPORT = transport;
                        deviceInfo.obj = name;
                        removeFoundDevice(deviceInfo);

                    }

                    @Override
                    public void foundAdvertisedName(String name, short transport, String namePrefix) {
                        logInfo(String.format("MyBusListener.foundAdvertisedName(%s, 0x%04x, %s)", name, transport,
                                namePrefix));

                        //                        Service service = new Service(name);
                        //                        service.setTransport(transport);
                        //                        service.setWellKnownNamePrefix(namePrefix);
                        //                        serviceArrayList.add(service);
                        //
                        //                        for (Service service1: serviceArrayList) {
                        //                            Log.d("serviceArrayList",service1.getWellKnownName());
                        //                        }

                        Message deviceInfo = obtainMessage(MESSAGE_ADD_FOUND_DEVICE);
                        deviceInfo.arg1 = transport;
                        deviceInfo.obj = name;
                        DEVICE_TRANSPORT = transport;
                        addFoundDevice(deviceInfo);

                    }
                });

                /* To communicate with AllJoyn objects, we must connect the BusAttachment to the bus. */
                Status status = mBus.connect();
                logStatus("BusAttachment.connect()", status);
                if (Status.OK != status) {
                    finish();
                    return;
                }

                /*
                 * Now find an instance of the AllJoyn object we want to call.  We start by looking for
                 * a name, then connecting to the device that is advertising that name.
                 *
                 * In this case, we are looking for the well-known SERVICE_NAME.
                 */

                status = mBus.findAdvertisedName(SERVICE_NAME);
                logStatus(String.format("BusAttachement.findAdvertisedName(%s)", SERVICE_NAME), status);
                if (Status.OK != status) {
                    finish();
                    return;
                }

                break;
            }
            case (JOIN_SESSION): {
                /*
                  * If discovery is currently being stopped don't join to any other sessions.
                  */
                if (mIsStoppingDiscovery) {
                    break;
                }

                /*
                 * In order to join the session, we need to provide the well-known
                 * contact port.  This is pre-arranged between both sides as part
                 * of the definition of the chat service.  As a result of joining
                 * the session, we get a session identifier which we must use to 
                 * identify the created session communication channel whenever we
                 * talk to the remote side.
                 */

                if (mIsConnected) {
                    Status status = mBus.leaveSession(mSessionId);
                    logStatus("BusAttachment.leaveSession()", status);
                }

                String[] tokens = ((String) msg.obj).split("[.]"); // msg.obj = "com.flybits.devices.coffeemaker.My_Coffee_Maker
                mDeviceType = tokens[tokens.length - 2]; // coffeemaker
                mDeviceName = String.valueOf(msg.obj); // "com.flybits.devices.coffeemaker.My_Coffee_Maker"

                interfaceSelector(mDeviceType, mDeviceName, mSessionId, false);

                short contactPort = CONTACT_PORT;
                SessionOpts sessionOpts = new SessionOpts();
                sessionOpts.transports = (short) msg.arg1;
                Mutable.IntegerValue sessionId = new Mutable.IntegerValue();

                Status status = mBus.joinSession(mDeviceName, contactPort, sessionId, sessionOpts,
                        new SessionListener() {

                            @Override
                            public void sessionLost(int sessionId) {
                                mIsConnected = false;
                                logInfo(String.format("MyBusListener.sessionLost(%d)", sessionId));
                                mHandler.sendEmptyMessage(MESSAGE_START_PROGRESS_DIALOG);
                            }
                        });
                logStatus("BusAttachment.joinSession() - sessionId: " + sessionId.value, status);

                if (status == Status.OK) {
                    /*
                      * To communicate with an AllJoyn object, we create a ProxyBusObject.
                      * A ProxyBusObject is composed of a name, path, sessionID and interfaces.
                      *
                      * This ProxyBusObject is located at the well-known SERVICE_NAME, under path
                      * "/SimpleService", uses sessionID of CONTACT_PORT, and implements the SimpleInterface.
                      */

                    //  Select the appropriate Bus Interface based on the Device Type,
                    interfaceSelector(mDeviceType, mDeviceName, sessionId.value, true);
                    mSessionId = sessionId.value;
                    mIsConnected = true;
                    mHandler.sendEmptyMessage(MESSAGE_STOP_PROGRESS_DIALOG);
                }
                break;
            }

            /* Release all resources acquired in the connect. */
            case DISCONNECT: {
                mIsStoppingDiscovery = true;
                if (mIsConnected) {
                    Status status = mBus.leaveSession(mSessionId);
                    logStatus("BusAttachment.leaveSession()", status);
                }
                mBus.disconnect();
                getLooper().quit();
                break;
            }

            /*
             * Call the service's Ping method through the ProxyBusObject.
             *
             * This will also print the String that was sent to the service and the String that was
             * received from the service to the user interface.
             */
            case PING: {
                try {
                    if (mSimpleInterface != null) {
                        sendUiMessage(MESSAGE_PING, msg.obj);
                        String reply = mSimpleInterface.Ping((String) msg.obj);
                        sendUiMessage(MESSAGE_PING_REPLY, reply);
                        //String deviceName = mSimpleInterface.GetDeviceName();
                        //Log.i("Device Name", deviceName);

                    }

                } catch (BusException ex) {
                    logException("SimpleInterface.Ping()", ex);
                }
                break;
            }

            case GET_DEVICE_NAME: {
                try {
                    if (mCoffeeMakerInterface != null) {
                        mBundle = new Bundle();

                        String nameReply = mCoffeeMakerInterface.getDeviceName();
                        Log.d("handleMessage", nameReply);
                        mBundle.putCharSequence("Name", nameReply);

                        String potReply = mCoffeeMakerInterface.getPotStatus();
                        Log.d("handleMessage", potReply);
                        String lidReply = mCoffeeMakerInterface.getLidStatus();
                        Log.d("handleMessage", lidReply);
                        String powerReply = mCoffeeMakerInterface.getPowerStatus();
                        Log.d("handleMessage", powerReply);
                        String waterReply = mCoffeeMakerInterface.getWaterLevel();
                        Log.d("handleMessage", waterReply);
                        mHandler.sendEmptyMessage(MESSAGE_UPDATE_DETAILSFRAGMENT_UI);

                    }
                    if (mThermostatInterface != null) {
                        mBundle = new Bundle();
                        mBundle.putCharSequence("Interface", "Thermostat");
                        String nameReply = mThermostatInterface.getDeviceName();
                        Log.d("handleMessage", nameReply);
                        mBundle.putCharSequence("Name", nameReply);
                        String tempReply = mThermostatInterface.getTemperature();
                        Log.d("handleMessage", tempReply);
                        mBundle.putCharSequence("Temperature", tempReply);
                        mHandler.sendEmptyMessage(MESSAGE_UPDATE_DETAILSFRAGMENT_UI);

                    }
                    if (mSimpleInterface != null) {
                        String reply = mSimpleInterface.getDeviceName();
                        Log.d("handleMessage", reply);
                    }
                } catch (BusException ex) {
                    logException("SimpleInterface.GetSDFSDF()", ex);

                }
            }

            default:
                break;
            }
        }

        /* Helper function to send a message to the UI thread. */
        private void sendUiMessage(int what, Object obj) {
            mHandler.sendMessage(mHandler.obtainMessage(what, obj));
        }
    }

    private void logStatus(String msg, Status status) {
        String log = String.format("%s: %s", msg, status);
        if (status == Status.OK) {
            Log.i(TAG, log);
        } else {
            Message toastMsg = mHandler.obtainMessage(MESSAGE_POST_TOAST, log);
            mHandler.sendMessage(toastMsg);
            Log.e(TAG, log);
        }
    }

    private void logException(String msg, BusException ex) {
        String log = String.format("%s: %s", msg, ex);
        Message toastMsg = mHandler.obtainMessage(MESSAGE_POST_TOAST, log);
        mHandler.sendMessage(toastMsg);
        Log.e(TAG, log, ex);
    }

    /*
     * print the status or result to the Android log. If the result is the expected
     * result only print it to the log.  Otherwise print it to the error log and
     * Sent a Toast to the users screen. 
     */
    private void logInfo(String msg) {
        Log.i(TAG, msg);
    }
}