Java tutorial
// Copyright 2016 Shawn Baker using the MIT License. package ca.frozen.curlingtv.activities; import android.app.Dialog; import android.app.DialogFragment; import android.content.DialogInterface; import android.os.AsyncTask; import android.os.Bundle; import android.os.Handler; import android.os.SystemClock; import android.support.v4.content.ContextCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.view.Window; import android.widget.Button; import android.widget.ProgressBar; import android.widget.TextView; import java.lang.ref.WeakReference; import java.util.ArrayList; import java.util.List; import ca.frozen.curlingtv.App; import ca.frozen.curlingtv.classes.Camera; import ca.frozen.curlingtv.classes.Connection; import ca.frozen.curlingtv.classes.Settings; import ca.frozen.curlingtv.classes.Utils; import ca.frozen.curlingtv.R; public class ScannerFragment extends DialogFragment { // local constants private final static String TAG = "ScannerFragment"; // instance variables private WeakReference<DeviceScanner> scannerWeakRef; private TextView message, status; private ProgressBar progress; private Button cancelButton = null; private Runnable dismissRunner; private Handler dismissHandler = new Handler(); //****************************************************************************** // onCreate //****************************************************************************** @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setRetainInstance(true); // load the settings and cameras Utils.loadData(); // create and run the scanner asynchronously DeviceScanner scanner = new DeviceScanner(this); scannerWeakRef = new WeakReference<>(scanner); scanner.execute(); } //****************************************************************************** // onCreateView //****************************************************************************** @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { // get the controls View view = inflater.inflate(R.layout.fragment_scanner, container, false); message = (TextView) view.findViewById(R.id.scanner_message); status = (TextView) view.findViewById(R.id.scanner_status); progress = (ProgressBar) view.findViewById(R.id.scanner_progress); cancelButton = (Button) view.findViewById(R.id.scanner_cancel); // configure the dialog Dialog dialog = getDialog(); if (dialog != null) { dialog.requestWindowFeature(Window.FEATURE_NO_TITLE); dialog.setCancelable(false); dialog.setCanceledOnTouchOutside(false); dialog.setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(android.content.DialogInterface dialog, int keyCode, android.view.KeyEvent event) { if ((keyCode == android.view.KeyEvent.KEYCODE_BACK)) { cancel(); } return false; } }); } // handle the cancel button cancelButton.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { cancel(); dismiss(); } }); // create the dismiss handler and runnable dismissHandler = new Handler(); dismissRunner = new Runnable() { @Override public void run() { dismiss(); } }; // configure the view if we've already done the scan if (savedInstanceState != null) { DeviceScanner scanner = (scannerWeakRef != null) ? scannerWeakRef.get() : null; if (scanner != null) { boolean complete = scanner.isComplete(); scanner.setStatus(complete); if (complete) { cancelButton.setText(App.getStr(R.string.done)); } } } return view; } //****************************************************************************** // onDestroyView //****************************************************************************** @Override public void onDestroyView() { dismissHandler.removeCallbacks(dismissRunner); if (getDialog() != null && getRetainInstance()) { getDialog().setDismissMessage(null); } super.onDestroyView(); } //****************************************************************************** // cancel //****************************************************************************** private void cancel() { DeviceScanner scanner = (scannerWeakRef != null) ? scannerWeakRef.get() : null; if (scanner != null) { scanner.cancel(true); } } //////////////////////////////////////////////////////////////////////////////// // DeviceScanner //////////////////////////////////////////////////////////////////////////////// private class DeviceScanner extends AsyncTask<Void, Void, Void> { // local constants private final static String TAG = "DeviceScanner"; private final static int NO_DEVICE = -1; private final static int NUM_THREADS = 42; private final static int SLEEP_TIMEOUT = 10; private final static int DISMISS_TIMEOUT = 1500; // instance variables private WeakReference<ScannerFragment> fragmentWeakRef; private String ipAddress, network; private int device, numDone; private List<Camera> networkCameras, newCameras; private Settings settings; //****************************************************************************** // DeviceScanner //****************************************************************************** private DeviceScanner(ScannerFragment fragment) { fragmentWeakRef = new WeakReference<>(fragment); } //****************************************************************************** // onPreExecute //****************************************************************************** @Override protected void onPreExecute() { // get our IP address and the default port network = Utils.getNetworkName(); ipAddress = Utils.getLocalIpAddress(); settings = Utils.getSettings(); device = 0; numDone = 0; networkCameras = Utils.getNetworkCameras(network); newCameras = new ArrayList<>(); } //****************************************************************************** // doInBackground //****************************************************************************** @Override protected Void doInBackground(Void... params) { if (ipAddress != null && !ipAddress.isEmpty()) { int i = ipAddress.lastIndexOf('.'); final int myDevice = Integer.parseInt(ipAddress.substring(i + 1)); final String baseAddress = ipAddress.substring(0, i + 1); Runnable runner = new Runnable() { @Override public void run() { for (int dev = getNextDevice(); !isCancelled() && dev != NO_DEVICE; dev = getNextDevice()) { if (dev == myDevice) { doneDevice(dev); continue; } String address = baseAddress + Integer.toString(dev); // look for a TCP/IP connection try { // try to connect to the device Connection reader = new Connection(address, settings.port, Connection.QUERY_TIMEOUT); if (reader.isConnected()) { String name = reader.getName(); Camera camera = new Camera(network, name, address, settings.port); addCamera(camera); reader.close(); } } catch (Exception ex) { } doneDevice(dev); } } }; // create and start the threads for (int t = 0; t < NUM_THREADS; t++) { Thread thread = new Thread(runner); thread.start(); } // wait for the threads to finish while (!isCancelled() && numDone < 254) { SystemClock.sleep(SLEEP_TIMEOUT); } // add the new cameras if (!isCancelled() && newCameras.size() > 0) { addCameras(); } setStatus(true); } return null; } //****************************************************************************** // onPostExecute //****************************************************************************** @Override protected void onPostExecute(Void unused) { final MainActivity activity = getActivity(cancelButton); if (activity != null) { activity.runOnUiThread(new Runnable() { public void run() { cancelButton.setText(App.getStr(R.string.done)); if (newCameras.size() > 0) { activity.updateCameras(); dismissHandler.postDelayed(dismissRunner, DISMISS_TIMEOUT); } } }); } } //****************************************************************************** // addCameras //****************************************************************************** private void addCameras() { // add the new cameras to the list of all cameras List<Camera> allCameras = Utils.getCameras(); for (Camera camera : newCameras) { allCameras.add(camera); } } //****************************************************************************** // addCamera //****************************************************************************** private synchronized void addCamera(Camera newCamera) { boolean found = false; for (Camera camera : networkCameras) { if (newCamera.address.equals(camera.address) && newCamera.port == camera.port) { found = true; break; } } if (!found) { newCameras.add(newCamera); } } //****************************************************************************** // getNextDevice //****************************************************************************** private synchronized int getNextDevice() { if (device < 254) { device++; return device; } return NO_DEVICE; } //****************************************************************************** // doneDevice //****************************************************************************** private synchronized void doneDevice(int device) { numDone++; setStatus(false); } //****************************************************************************** // setStatus //****************************************************************************** private synchronized void setStatus(final boolean last) { MainActivity activity = getActivity(status); if (activity != null) { activity.runOnUiThread(new Runnable() { public void run() { message.setText(String.format(App.getStr(R.string.scanning_on_port), settings.port)); progress.setProgress(numDone); status.setText( String.format(App.getStr(R.string.num_new_cameras_found), newCameras.size())); if (newCameras.size() > 0) { status.setTextColor(ContextCompat.getColor(App.getContext(), R.color.good_text)); } else if (last) { status.setTextColor(ContextCompat.getColor(App.getContext(), R.color.bad_text)); } } }); } } //****************************************************************************** // getActivity //****************************************************************************** private MainActivity getActivity(View view) { MainActivity activity = null; if (view != null) { ScannerFragment fragment = (fragmentWeakRef != null) ? fragmentWeakRef.get() : null; if (fragment != null) { activity = (MainActivity) fragment.getActivity(); } } return activity; } //****************************************************************************** // isComplete //****************************************************************************** public boolean isComplete() { return device == 255; } } }