/*
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of
* the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2014 Digi International Inc., All Rights Reserved.
*/
package com.digi.android.wva.fragments;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ListView;
import com.actionbarsherlock.app.SherlockListFragment;
import com.actionbarsherlock.view.Menu;
import com.actionbarsherlock.view.MenuInflater;
import com.actionbarsherlock.view.MenuItem;
import com.digi.addp.AddpClient;
import com.digi.addp.AddpDevice;
import com.digi.android.wva.DashboardActivity;
import com.digi.android.wva.R;
import com.digi.android.wva.WvaApplication;
import com.digi.android.wva.adapters.DeviceAdapter;
import com.digi.android.wva.util.RefreshManager;
import java.util.ArrayList;
import java.util.Hashtable;
import java.util.List;
import java.util.Map;
/**
* {@link SherlockListFragment Fragment} used specifically in
* {@link com.digi.android.wva.DeviceListActivity DeviceListActivity} to
* use ADDP to discover devices on the network and display information about
* them, as well as allow the user to select one of these devices to launch
* {@link DashboardActivity} and connect to that device.
* @author mwadsten
*
*/
public class DeviceDiscoveryFragment extends SherlockListFragment {
private static final String TAG = "DeviceDiscoveryFragment";
private DeviceAdapter mAdapter;
private RefreshManager mRefresh;
private MenuItem mRefreshItem;
private boolean isRefreshing;
@SuppressWarnings("UnusedDeclaration")
public static DeviceDiscoveryFragment newInstance() {
return new DeviceDiscoveryFragment();
}
/**
* Get the {@link RefreshManager} in use
* @return the {@link RefreshManager} instance in use.
*/
public RefreshManager getRefreshManager() {
return mRefresh;
}
/**
* Get the MenuItem used by the RefreshManager -- this is necessary
* because pre-4.0 action bar menu items cannot be invoked by the
* instrumentation invokeMenuActionSync, so we need to call
* onOptionsItemSelected manually.
* @return the {@link MenuItem} tied to the {@link RefreshManager}
*/
public MenuItem getRefreshItem() {
return mRefreshItem;
}
@Override
public void onActivityCreated(Bundle savedInstanceState) {
// Log.i(TAG, "onActivityCreated, " + savedInstanceState);
super.onActivityCreated(savedInstanceState);
setListAdapter(mAdapter);
setEmptyText(getString(R.string.empty_dev_message));
}
@Override
public void onDestroyView() {
// Log.i(TAG, "onDestroyView");
super.onDestroyView();
setListAdapter(null);
}
@Override
public void onCreate(Bundle savedInstanceState) {
// Log.i(TAG, "onCreate, " + savedInstanceState);
// Need to create mRefresh here because on tablets (seemingly) the
// action bar gets built during super.onCreate, so onCreate- and
// onPrepareOptionsMenu are called before mRefresh is instantiated,
// and the refresh action view won't appear until onPrepareOptionsMenu
// is called again, if ever.
mRefresh = new RefreshManager();
super.onCreate(savedInstanceState);
// Don't destroy fragment, or something.
// stackoverflow.com/q/5704478
setRetainInstance(true);
mAdapter = (DeviceAdapter) getListAdapter();
if (mAdapter == null)
mAdapter = new DeviceAdapter(getActivity());
setListAdapter(mAdapter);
setHasOptionsMenu(true);
// Set the application ADDP client.
AddpClient client = new AddpClient();
client.setWaitTimeInSeconds(10);
((WvaApplication)getActivity().getApplication()).setAddpClient(client);
}
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
// Log.i(TAG, "onCreateOptionsMenu");
inflater.inflate(R.menu.devices_refresh, menu);
mRefreshItem = menu.findItem(R.id.refresh);
if (mRefresh != null)
mRefresh.setIcon(mRefreshItem);
}
@Override
public void onPrepareOptionsMenu(Menu menu) {
// Log.i(TAG, "onPrepareOptionsMenu");
if (mRefresh == null)
// We can't do much here if this is the case.
return;
MenuItem refresh = menu.findItem(R.id.refresh);
mRefresh.setIcon(refresh);
if (isRefreshing && mRefresh.isNotRefreshing()) {
// RefreshManager not set to refreshing.
// Most likely because options menu was not created
// when startDiscovery was called.
// Log.i("DeviceFragment", "calling setRefreshing again");
mRefresh.setRefreshing(true);
}
}
@Override
public void onListItemClick(ListView l, View v, int position, long id) {
super.onListItemClick(l, v, position, id);
AddpDevice device = (AddpDevice) l.getItemAtPosition(position);
if (device == null) {
// There is no item at position 'position'...
return;
}
// Launch the DashboardActivity.
Intent intent = new Intent(getActivity(), DashboardActivity.class);
intent.putExtra(DashboardActivity.INTENT_IP, device.getIPAddress().getHostAddress());
startActivity(intent);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.refresh:
startDiscovery();
return true;
default:
return false;
}
}
protected void startDiscovery() {
isRefreshing = true;
mRefresh.setRefreshing(true);
Log.d(TAG, "Starting discovery");
new GetDevicesTask().execute();
try {
setListShown(false);
} catch (Exception e) {
e.printStackTrace();
}
}
protected void endDiscovery(List<AddpDevice> devices) {
mRefresh.setRefreshing(false);
isRefreshing = false;
// Clear adapter and set its contents.
mAdapter.clear();
for (AddpDevice el : devices)
mAdapter.add(el);
mAdapter.notifyDataSetChanged();
try {
setListShown(true);
} catch (Exception e) {
e.printStackTrace();
}
}
private class GetDevicesTask extends AsyncTask<Void, Void, Map<String, AddpDevice>> {
protected Map<String, AddpDevice> doInBackground(Void... nothings) {
Log.d(TAG, "GetDevicesTask.doInBackground");
if (getActivity() == null) {
Log.d(TAG, "getActivity() returned null in doInBackground");
this.cancel(true);
// return empty Enumeration, because we're not going to find
// any devices anyway - can't get to an AddpClient.
return new Hashtable<String, AddpDevice>();
}
WvaApplication app = (WvaApplication) getActivity().getApplication();
AddpClient addpClient = app.getAddpClient();
if (addpClient == null) {
// if the addp client is null, we don't want to do anything,
// least of all trying to execute a discovery.
Log.d(TAG, "No AddpClient!");
this.cancel(true);
// return empty Enumeration just in case cancel doesn't work
return new Hashtable<String, AddpDevice>();
}
Map<String, AddpDevice> devices;
if (addpClient.searchForDevices()) {
devices = addpClient.getDevices();
} else {
devices = new Hashtable<String, AddpDevice>();
}
Log.d(TAG, "Discovered " + devices.size() + " devices.");
return devices;
}
protected void onPostExecute(Map<String, AddpDevice> deviceMap) {
if (isCancelled()) {
Log.i(TAG, "Discovery task was cancelled.");
return;
}
List<AddpDevice> lis = new ArrayList<AddpDevice>();
for (AddpDevice dev : deviceMap.values()) {
if (dev.getIPAddress() == null) {
continue;
}
lis.add(dev);
Log.d(TAG, "Found device: "
+ dev.getDeviceID() + " "
+ dev.getHardwareName() + " "
+ dev.getIPAddress().getHostAddress());
}
endDiscovery(lis);
}
}
}