mobisocial.musubi.ui.NearbyActivity.java Source code

Java tutorial

Introduction

Here is the source code for mobisocial.musubi.ui.NearbyActivity.java

Source

/*
 * Copyright 2012 The Stanford MobiSocial Laboratory
 *
 * 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 mobisocial.musubi.ui;

import java.util.ArrayList;

import mobisocial.metrics.MusubiMetrics;
import mobisocial.metrics.UsageMetrics;
import mobisocial.musubi.BJDNotImplementedException;
import mobisocial.musubi.R;
import mobisocial.musubi.model.DbContactAttributes;
import mobisocial.musubi.nearby.NearbyLookup;
import mobisocial.musubi.nearby.NearbyLookup.NearbyResultListener;
import mobisocial.musubi.nearby.broadcast.MulticastBroadcastTask;
import mobisocial.musubi.nearby.item.NearbyItem;
import mobisocial.musubi.util.ActivityCallout;
import mobisocial.musubi.util.BluetoothBeacon;
import mobisocial.musubi.util.InstrumentedActivity;
import mobisocial.musubi.util.Util;

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

import android.app.Activity;
import android.app.AlertDialog;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.wifi.WifiInfo;
import android.net.wifi.WifiManager;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.MenuInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.CheckBox;
import android.widget.CompoundButton;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.google.zxing.integration.android.IntentIntegrator;
import com.google.zxing.integration.android.IntentResult;

/**
 * Shows groups and users that have been found nearby.
 * 
 * TODO: GetNearbyDevicesTask
 *    onDeviceDiscovered(User d) {
 *    }
 */
public class NearbyActivity extends MusubiBaseActivity implements InstrumentedActivity, OnItemClickListener {
    private static final String TAG = "Nearby";
    private static boolean DBG = true;

    private NearbyAdapter mAdapter;
    private final ArrayList<NearbyItem> mNearbyList = new ArrayList<NearbyItem>();
    private static final int RESULT_BT_ENABLE = 1;

    private MulticastBroadcastTask mMulticastBroadcaster;
    private WifiManager mWifiManager;
    NearbyLookup.LookupFuture mNearbyLookup;

    public void onClickHome(View v) {
        goHome(this);
    }

    public void goHome(Context context) {
        final Intent intent = new Intent(context, FeedListActivity.class);
        if (Build.VERSION.SDK_INT < 11)
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        else
            intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_nearby);

        mWifiManager = (WifiManager) getSystemService(Context.WIFI_SERVICE);

        findViewById(R.id.qr).setOnClickListener(new OnClickListener() {
            @Override
            public void onClick(View v) {
                IntentIntegrator.initiateScan(NearbyActivity.this);
            }
        });
        findViewById(R.id.qr).setVisibility(View.GONE);
        findViewById(R.id.go).setVisibility(View.GONE);

        DBG = MusubiBaseActivity.isDeveloperModeEnabled(this);
        setTitle("Nearby");
        mAdapter = new NearbyAdapter(this, R.layout.nearby_groups_item, mNearbyList);

        ListView lv = (ListView) findViewById(android.R.id.list);
        lv.setAdapter(mAdapter);
        lv.setOnItemClickListener(this);

        if (true) {
            findViewById(R.id.social).setVisibility(View.GONE);
        } else {
            setupMulticastScanner();
        }
        EditText tv = (EditText) findViewById(R.id.password);
        tv.addTextChangedListener(new TextWatcher() {
            @Override
            public void onTextChanged(CharSequence s, int start, int before, int count) {
            }

            @Override
            public void beforeTextChanged(CharSequence s, int start, int count, int after) {
            }

            @Override
            public void afterTextChanged(Editable s) {
                synchronized (NearbyActivity.this) {
                    mNearbyList.clear();
                    mAdapter.notifyDataSetChanged();
                }
                scanNearby();
            }
        });

        if (savedInstanceState == null) {
            UsageMetrics.getUsageMetrics(this).report(MusubiMetrics.VISITED_NEARBY);
        }

        String provider = Settings.Secure.getString(getContentResolver(),
                Settings.Secure.LOCATION_PROVIDERS_ALLOWED);
        if (provider == null || !provider.contains("gps") || !provider.contains("network")) {
            new AlertDialog.Builder(this).setTitle("Location Settings").setMessage(
                    "You should enable both network-based and GPS-based location services to ensure you can find nearby groups.")
                    .setNegativeButton("Cancel", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                        }
                    }).setPositiveButton("Go to Settings", new DialogInterface.OnClickListener() {
                        @Override
                        public void onClick(DialogInterface dialog, int which) {
                            try {
                                Intent myIntent = new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS);
                                startActivity(myIntent);
                            } catch (Throwable t) {
                                Log.e(TAG, "failed to launch location settings", t);
                            }
                        }
                    }).show();
        }
    }

    private void setupMulticastScanner() {
        CheckBox checkbox = (CheckBox) findViewById(R.id.social);
        mMulticastBroadcaster = MulticastBroadcastTask.getInstance(NearbyActivity.this);
        if (mMulticastBroadcaster.isRunning()) {
            checkbox.setChecked(true);
        }
        checkbox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {
            @Override
            public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {
                // TODO: Generalize to NearbyBroadcaster; do multicast, bt, gps, dns
                if (buttonView.isChecked()) {
                    if (mMulticastBroadcaster == null) {
                        mMulticastBroadcaster = MulticastBroadcastTask.getInstance(NearbyActivity.this);
                    }
                    mMulticastBroadcaster.execute();
                } else {
                    mMulticastBroadcaster.cancel(true);
                    mMulticastBroadcaster = null;
                }
            }
        });
    }

    @Override
    public boolean onCreateOptionsMenu(android.support.v4.view.Menu menu) {
        MenuInflater inflater = getMenuInflater();
        inflater.inflate(R.menu.nearby_activity, menu);
        menu.findItem(R.id.menu_pin).setVisible(false);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(android.support.v4.view.MenuItem item) {
        Log.d(TAG, " item " + item);
        switch (item.getItemId()) {
        case R.id.menu_refresh: {
            synchronized (NearbyActivity.this) {
                mNearbyList.clear();
                mAdapter.notifyDataSetChanged();
            }
            scanNearby();
            return true;
        }
        case R.id.menu_pin: {
            doCheckin();
            return true;
        }
        }
        return super.onOptionsItemSelected(item);
    }

    private void doCheckin() {
        WifiInfo wifi = mWifiManager.getConnectionInfo();
        String myWifiName = wifi.getSSID();
        if (myWifiName == null) {
            /**
             * TODO:
             * Depending on desired outcome, either help them get on wifi
             * or try connecting to gps server, etc.
             */
            toast("No wifi network available.");
            return;
        }

        String myWifiId = wifi.getBSSID();
        String myIp = formatIp(wifi.getIpAddress());
        String myWifiFingerprint = Util.computeWifiFingerprint(mWifiManager.getScanResults());

        if (DBG)
            Log.d(TAG, "Checking in to " + myWifiName + "...");
        JSONObject loc = new JSONObject();
        try {
            loc.put(DbContactAttributes.ATTR_WIFI_SSID, myWifiName);
            if (myWifiId != null) {
                loc.put(DbContactAttributes.ATTR_WIFI_BSSID, myWifiId);
            }
            if (myIp != null) {
                loc.put(DbContactAttributes.ATTR_LAN_IP, myIp);
            }
            loc.put(DbContactAttributes.ATTR_WIFI_FINGERPRINT, myWifiFingerprint);
        } catch (JSONException e) {
            // Impossible json exception
        }

        //XXX killed for now
        //mMusubi.getAppFeed().postObj(new MemObj("locUpdate", loc));
        //toast("Checked in to '" + myWifiName + "'.");
    }

    private String formatIp(int ip) {
        return String.format("%d.%d.%d.%d", (ip & 0xff), (ip >> 8 & 0xff), (ip >> 16 & 0xff), (ip >> 24 & 0xff));
    }

    private void scanNearby() {
        if (DBG)
            Log.d(TAG, "initiating nearby scan...");
        String password = ((EditText) findViewById(R.id.password)).getText().toString();

        if (mNearbyLookup != null) {
            mNearbyLookup.cancel(true);
        }
        NearbyLookup lookup = new NearbyLookup(this, password);
        mNearbyLookup = lookup.doLookup(mLookupResultListener);
    }

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

        mAdapter.notifyDataSetChanged();
        scanNearby();
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mNearbyLookup != null) {
            mNearbyLookup.cancel(true);
            mNearbyLookup = null;
        }
    }

    @Override
    public void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ACTIVITY_CALLOUT) {
            mCurrentCallout.handleResult(resultCode, data);
            return;
        }

        IntentResult result = IntentIntegrator.parseActivityResult(requestCode, resultCode, data);
        if (result != null && result.getContents() != null) {
            try {
                Uri uri = Uri.parse(result.getContents());
                Intent i = new Intent(Intent.ACTION_VIEW, uri);
                i.setPackage(getPackageName());
                startActivity(i);
                finish();
            } catch (IllegalArgumentException e) {
            }
            return;
        }
        if (requestCode == RESULT_BT_ENABLE) {
            if (resultCode == Activity.RESULT_CANCELED) {
                finish();
            } else {
                findBluetooth();
            }
        }
    }

    private NearbyResultListener mLookupResultListener = new NearbyResultListener() {
        @Override
        public void onItemDiscovered(NearbyItem item) {
            mNearbyList.add(item);
            mAdapter.notifyDataSetChanged();
        }

        @Override
        public void onDiscoveryComplete() {
        }

        @Override
        public void onDiscoveryBegin() {
            mNearbyList.clear();
            mAdapter.notifyDataSetChanged();
        }
    };

    private class NearbyAdapter extends ArrayAdapter<NearbyItem> {
        private ArrayList<NearbyItem> nearby;

        public NearbyAdapter(Context context, int textViewResourceId, ArrayList<NearbyItem> groups) {
            super(context, textViewResourceId, groups);
            this.nearby = groups;
        }

        @Override
        public View getView(int position, View convertView, ViewGroup parent) {
            View row = convertView;
            if (convertView == null) {
                LayoutInflater vi = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                row = vi.inflate(R.layout.nearby_groups_item, null);
            }
            final NearbyItem g = nearby.get(position);
            TextView text = (TextView) row.findViewById(R.id.name_text);
            text.setText(g.name);
            TextView dtext = (TextView) row.findViewById(R.id.detail_text);
            dtext.setText(g.getDetail());
            ((ImageView) row.findViewById(R.id.icon)).setImageBitmap(g.getIcon());
            return row;
        }
    }

    @Override
    public void onItemClick(AdapterView<?> adapterView, View view, int position, long id) {
        NearbyItem g = mAdapter.getItem(position);
        g.view(this);
    }

    private void findBluetooth() {
        if (!BluetoothAdapter.getDefaultAdapter().isEnabled()) {
            Intent bt = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(bt, RESULT_BT_ENABLE);
            return;
        }

        // Create a BroadcastReceiver for ACTION_FOUND
        final IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
        filter.addAction(BluetoothAdapter.ACTION_STATE_CHANGED);

        final BroadcastReceiver receiver = new BroadcastReceiver() {
            public void onReceive(final Context context, final Intent intent) {
                String action = intent.getAction();
                // When discovery finds a device
                if (BluetoothDevice.ACTION_FOUND.equals(action)) {
                    new Thread() {
                        public void run() {
                            BluetoothBeacon.OnDiscovered discovered = new BluetoothBeacon.OnDiscovered() {
                                @Override
                                public void onDiscovered(final byte[] data) {
                                    runOnUiThread(new Runnable() {
                                        @Override
                                        public void run() {
                                            try {
                                                JSONObject obj = new JSONObject(new String(data));
                                                BJDNotImplementedException.except("bluetooth not implemented");
                                                //                                                mNearbyList.add(new NearbyFeed(NearbyActivity.this,
                                                //                                                        obj.getString("name"), Uri.parse(obj
                                                //                                                                .getString("dynuri"))));
                                                mAdapter.notifyDataSetChanged();
                                            } catch (JSONException e) {
                                                Log.e(TAG, "Error getting group info over bluetooth", e);
                                            }
                                        }
                                    });
                                }
                            };
                            // Get the BluetoothDevice object from the Intent
                            BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
                            BluetoothBeacon.discover(NearbyActivity.this, device, discovered);
                        };
                    }.start();
                }
                if (BluetoothAdapter.ACTION_STATE_CHANGED.equals(action)) {
                    unregisterReceiver(this);
                }
            }
        };

        registerReceiver(receiver, filter); // Don't forget to unregister during
                                            // onDestroy
        BluetoothAdapter.getDefaultAdapter().startDiscovery();
        Toast.makeText(this, "Scanning Bluetooth...", 500).show();
    }

    private static int REQUEST_ACTIVITY_CALLOUT = 39;
    private static ActivityCallout mCurrentCallout;

    public void doActivityForResult(ActivityCallout callout) {
        mCurrentCallout = callout;
        Intent launch = callout.getStartIntent();
        startActivityForResult(launch, REQUEST_ACTIVITY_CALLOUT);
    }
}