Java tutorial
/******************************************************************************* * Copyright 2014 Norbert Pabian. * * 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 * imitations under the License. ******************************************************************************/ package com.nps.micro; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import android.app.Activity; import android.app.PendingIntent; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.content.SharedPreferences; import android.content.res.Configuration; import android.hardware.usb.UsbConstants; import android.hardware.usb.UsbDevice; import android.hardware.usb.UsbManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.preference.PreferenceManager; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.app.FragmentManager; import android.support.v4.app.FragmentPagerAdapter; import android.support.v4.view.ViewPager; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.WindowManager; import com.nps.micro.UsbService.Status; import com.nps.micro.view.AboutFragmentListener; import com.nps.micro.view.AboutSectionFragment; import com.nps.micro.view.BaseSectionFragment; import com.nps.micro.view.Dialogs; import com.nps.micro.view.GraphFragmentListener; import com.nps.micro.view.GraphSectionFragment; import com.nps.micro.view.TestsFragmentListener; import com.nps.micro.view.TestsSectionFragment; import com.nps.scenario.Scenario; import com.nps.usb.AtmelSam3DeviceId; import com.nps.usb.AtmelSam7DeviceId; import com.nps.usb.DeviceId; import com.nps.usb.STM32DeviceId; /** * @author Norbert Pabian * www.npsoft.clanteam.com */ public class MainActivity extends FragmentActivity { public static final String PACKAGE = "com.nps.micro"; private static final String ACTION_USB_PERMISSION = PACKAGE + ".USB_PERMISSION"; private static final String TAG = "MainActivity"; private static final int USER_PREFERENCES = 123; private UsbService microUsbService; private Intent usbServiceIntent; private Messenger messengerService; private boolean isDeviceAvailable = false; private boolean isBoundToService; private List<DeviceId> deviceIds = new ArrayList<DeviceId>(); List<UsbDevice> devices = new ArrayList<UsbDevice>(); List<UsbDevice> devicesWithoutPermisions = new ArrayList<UsbDevice>(); List<UsbDevice> devicesWithPermisions = new ArrayList<UsbDevice>(); private final Messenger messenger = new Messenger(new IncomingHandler()); private BroadcastReceiver usbDisconnectedBroadcastReceiver; private class UsbDisconnectedBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "UsbBroadcastReceiver"; private final Activity activity; public UsbDisconnectedBroadcastReceiver(Activity activity) { this.activity = activity; } public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action)) { UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (isExpectedDevice(device)) { Log.d(TAG, "USB device disconnected: " + device); stopUsbService(); Dialogs.getDeviceDisconnectedDialog(activity).show(); } } } }; private final BroadcastReceiver usbPermissionBroadcastReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { String action = intent.getAction(); if (ACTION_USB_PERMISSION.equals(action)) { synchronized (this) { UsbDevice device = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { devicesWithoutPermisions.remove(0); devicesWithPermisions.add(device); requestPermisionForDevice(); } else { Log.d(TAG, "permission denied for device " + device); } } } } }; private ServiceConnection usbServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder service) { // This is called when the connection with the service has been // established, giving us the service object we can use to // interact with the service. Because we have bound to a explicit // service that we know is running in our own process, we can // cast its IBinder to a concrete class and directly access it. microUsbService = ((UsbService.LocalBinder) service).getService(); mSectionsPagerAdapter.updateAvailabeDevices(microUsbService.getAvailableMicrocontrollers()); messengerService = new Messenger(((UsbService.LocalBinder) service).getMessenger()); try { Message msg = Message.obtain(null, UsbService.MSG_REGISTER_CLIENT); msg.replyTo = messenger; messengerService.send(msg); Status status = microUsbService.getStatus(); mSectionsPagerAdapter.updateStatus(status.getText(), status.isBusy()); } catch (RemoteException e) { // In this case the service has crashed before we could even do // anything with it } } @Override public void onServiceDisconnected(ComponentName className) { // This is called when the connection with the service has been // unexpectedly disconnected -- that is, its process crashed. // Because it is running in our same process, we should never // see this happen. messengerService = null; microUsbService = null; } }; private static class IncomingHandler extends Handler { @Override public void handleMessage(Message msg) { switch (msg.what) { case UsbService.MSG_STATUS: Bundle b = msg.getData(); mSectionsPagerAdapter.updateStatus(b.getString(UsbService.MSG_STATUS_CONTENT), b.getBoolean(UsbService.MSG_STATUS_BUSY)); break; default: super.handleMessage(msg); } } } /** * The {@link android.support.v4.view.PagerAdapter} that will provide * fragments for each of the sections. We use a * {@link android.support.v4.app.FragmentPagerAdapter} derivative, which * will keep every loaded fragment in memory. If this becomes too memory * intensive, it may be best to switch to a * {@link android.support.v4.app.FragmentStatePagerAdapter}. */ private static SectionsPagerAdapter mSectionsPagerAdapter; /** * The {@link ViewPager} that will host the section contents. */ ViewPager mViewPager; private UsbManager usbManager; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Create the adapter that will return a fragment for each of the three // primary sections of the app. mSectionsPagerAdapter = new SectionsPagerAdapter(getSupportFragmentManager()); // Set up the ViewPager with the sections adapter. mViewPager = (ViewPager) findViewById(R.id.pager); mViewPager.setAdapter(mSectionsPagerAdapter); usbDisconnectedBroadcastReceiver = new UsbDisconnectedBroadcastReceiver(this); registerReceiver(usbDisconnectedBroadcastReceiver, new IntentFilter(UsbManager.ACTION_USB_DEVICE_DETACHED)); initUsbService(); } private void initSupportedDeviceIds() { SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(this); if (prefs.getBoolean("atmel1_dev", false)) { deviceIds.add(new AtmelSam7DeviceId()); } if (prefs.getBoolean("atmel2_dev", false)) { deviceIds.add(new AtmelSam3DeviceId()); } if (prefs.getBoolean("stm_dev", false)) { deviceIds.add(new STM32DeviceId()); } for (int i = 1; i <= 3; i++) { if (prefs.getBoolean("custom" + i + "_dev", false)) { deviceIds.add( new DeviceId("Custom", Integer.valueOf(prefs.getString("custom" + i + "_dev_pid", "0")), Integer.valueOf(prefs.getString("custom" + i + "_dev_vid", "0")))); } } } private void initUsbService() { usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); initSupportedDeviceIds(); initUsbDevices(); } private void startUsbService() { isDeviceAvailable = true; Log.d(TAG, "Setup USB service."); usbServiceIntent = new Intent(this, UsbService.class); usbServiceIntent.putExtra(PACKAGE + '.' + "numberOfDevices", devices.size()); for (int i = 0; i < devicesWithPermisions.size(); i++) { usbServiceIntent.putExtra(PACKAGE + '.' + "device" + i, devicesWithPermisions.get(i).getDeviceName()); } Log.d(TAG, "Starting nps usb service..."); startService(usbServiceIntent); } private boolean isExpectedDevice(UsbDevice device) { if (device == null) { return false; } for (DeviceId devId : deviceIds) { if (devId.equals(device)) { for (int i = 0; i < device.getInterfaceCount(); i++) { if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) { return true; } } } } return false; } private void initUsbDevices() { HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList(); Iterator<UsbDevice> deviceIterator = deviceList.values().iterator(); while (deviceIterator.hasNext()) { UsbDevice dev = deviceIterator.next(); if (isExpectedDevice(dev)) { devices.add(dev); } } if (!devices.isEmpty()) { devicesWithoutPermisions = new ArrayList<UsbDevice>(devices); requestPermisionForDevice(); } else { Log.d(TAG, "Cannot find target USB device"); Dialogs.getUsbDeviceNotFoundDialog(this).show(); } } private void requestPermisionForDevice() { if (devicesWithoutPermisions.isEmpty()) { startUsbService(); bindToUsbService(); return; } UsbDevice dev = devicesWithoutPermisions.get(0); if (usbManager.hasPermission(dev)) { devicesWithPermisions.add(devicesWithoutPermisions.get(0)); devicesWithoutPermisions.remove(0); requestPermisionForDevice(); } else { PendingIntent permissionIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION); registerReceiver(usbPermissionBroadcastReceiver, filter); usbManager.requestPermission(dev, permissionIntent); } } @Override protected void onStart() { super.onStart(); bindToUsbService(); } @Override protected void onResume() { super.onResume(); bindToUsbService(); if (getWindow().getAttributes().softInputMode == WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) { getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN); } } @Override protected void onPause() { super.onPause(); unbindFromUsbService(); } @Override protected void onStop() { super.onStop(); unbindFromUsbService(); } @Override protected void onDestroy() { stopUsbService(); if (usbDisconnectedBroadcastReceiver != null) { try { unregisterReceiver(usbDisconnectedBroadcastReceiver); } catch (Exception e) { Log.d(TAG, "Cannot unregister receiver: " + e.getMessage()); } } super.onDestroy(); } private void stopUsbService() { if (UsbService.isRunning() && usbServiceIntent != null) { stopService(usbServiceIntent); } if (usbPermissionBroadcastReceiver != null) { try { unregisterReceiver(usbPermissionBroadcastReceiver); } catch (Exception e) { Log.d(TAG, "Cannot unregister receiver: " + e.getMessage()); } } } private void unbindFromUsbService() { if (isBoundToService) { Log.d(TAG, "Unbinding nps usb service..."); // If we have received the service, and hence registered with it, // then now is the time to unregister. if (messengerService != null) { try { Message msg = Message.obtain(null, UsbService.MSG_UNREGISTER_CLIENT); msg.replyTo = messengerService; messengerService.send(msg); } catch (RemoteException e) { Log.d(TAG, "Cannot unregister client from service: " + e.getMessage()); // There is nothing special we need to do if the service has // crashed. } } // Detach our existing connection. unbindService(usbServiceConnection); isBoundToService = false; } } private void bindToUsbService() { if (!isBoundToService && isDeviceAvailable) { Log.d(TAG, "Binding nps usb service..."); isBoundToService = bindService(new Intent(this, UsbService.class), usbServiceConnection, Context.BIND_AUTO_CREATE); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle item selection switch (item.getItemId()) { case R.id.action_settings: openApplicationSettings(); return true; case R.id.action_exit: openApplicationSettings(); return true; default: return super.onOptionsItemSelected(item); } } public void openApplicationSettings() { Intent i = new Intent(this, UserPreferenceActivity.class); startActivityForResult(i, USER_PREFERENCES); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { if (requestCode == USER_PREFERENCES) { if (resultCode == RESULT_OK) { Dialogs.getSettingsChangedDialog(this).show(); } } } /** * A {@link FragmentPagerAdapter} that returns a fragment corresponding to * one of the sections/tabs/pages. */ public class SectionsPagerAdapter extends FragmentPagerAdapter { private BaseSectionFragment[] fragments; private CharSequence[] titles = new CharSequence[] { getString(R.string.title_tests), getString(R.string.title_graph), getString(R.string.title_about) }; private TestsSectionFragment testsFragment; private GraphSectionFragment graphFragment; private AboutSectionFragment aboutFragment; public SectionsPagerAdapter(FragmentManager fm) { super(fm); graphFragment = new GraphSectionFragment(); graphFragment.setOnGraphFragmentListener(new GraphFragmentListener() { @Override public byte[] getLastReceivedPacket(String deviceName) { if (microUsbService != null) { return microUsbService.getLastReceivedPacket(deviceName); } return null; } }); aboutFragment = new AboutSectionFragment(); aboutFragment.setListener(new AboutFragmentListener() { @Override public void openSettings() { openApplicationSettings(); } }); testsFragment = new TestsSectionFragment(); testsFragment.setListener(new TestsFragmentListener() { @Override public void runUsbTest(List<Scenario> scenarios) { if (microUsbService != null) { microUsbService.testCommunication(scenarios); graphFragment.setAutoEnableGraph(testsFragment.isAutoEnableGraph()); } } @Override public void pingDevice(String deviceName) { if (microUsbService != null) { microUsbService.pingDevice(deviceName); } } }); fragments = new BaseSectionFragment[] { testsFragment, graphFragment, aboutFragment }; } public void updateStatus(String status, boolean busy) { for (BaseSectionFragment fragment : fragments) { fragment.updateStatus(status, busy); } } @Override public Fragment getItem(int position) { return fragments[position]; } @Override public int getCount() { return fragments.length; } @Override public CharSequence getPageTitle(int position) { return titles[position]; } public void updateAvailabeDevices(List<String> devices) { testsFragment.setAvailableDevices(devices); graphFragment.setAvailableDevices(devices); } } }