/** * Copyright (c) 2011, SOCIETIES Consortium (WATERFORD INSTITUTE OF TECHNOLOGY (TSSG), HERIOT-WATT UNIVERSITY (HWU), SOLUTA.NET * (SN), GERMAN AEROSPACE CENTRE (Deutsches Zentrum fuer Luft- und Raumfahrt e.V.) (DLR), Zavod za varnostne tehnologije * informacijske družbe in elektronsko poslovanje (SETCCE), INSTITUTE OF COMMUNICATION AND COMPUTER SYSTEMS (ICCS), LAKE * COMMUNICATIONS (LAKE), INTEL PERFORMANCE LEARNING SOLUTIONS LTD (INTEL), PORTUGAL TELECOM INOVAÇÃO, SA (PTIN), IBM Corp., * INSTITUT TELECOM (ITSUD), AMITEC DIACHYTI EFYIA PLIROFORIKI KAI EPIKINONIES ETERIA PERIORISMENIS EFTHINIS (AMITEC), TELECOM * ITALIA S.p.a.(TI), TRIALOG (TRIALOG), Stiftelsen SINTEF (SINTEF), NEC EUROPE LTD (NEC)) * All rights reserved. * * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following * conditions are met: * * 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following * disclaimer in the documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT * SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ package org.societies.android.platform.devicestatus; import java.util.ArrayList; import java.util.List; import java.util.Set; import org.societies.android.platform.R; import org.societies.android.platform.devicestatus.DeviceStatusServiceSameProcess.LocalBinder; import org.societies.android.api.utilities.ServiceMethodTranslator; import org.societies.android.api.internal.devicemonitor.IDeviceStatus; import org.societies.android.api.internal.devicemonitor.BatteryStatus; import org.societies.android.api.internal.devicemonitor.ProviderStatus; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; 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.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.BatteryManager; import android.os.Bundle; import android.os.IBinder; import android.os.Message; import android.os.Messenger; import android.os.RemoteException; import android.util.Log; import android.view.View; import android.widget.TextView; import android.widget.Toast; /** * @author Olivier Maridat (Trialog) * @date 28 nov. 2011 */ public class DeviceStatusActivity extends Activity { private TextView txtConnectivity; private TextView txtBattery; private TextView txtLocation; private boolean ipBoundToService = false; private IDeviceStatus targetIPService = null; private boolean opBoundToService = false; private Messenger targetOPService = null; private long serviceInvoke; private static final int NUM_SERVICE_INVOKES = 1; /* ************** * Activity Lifecycle * ************** */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); // -- Create a link with editable area txtConnectivity = (TextView) findViewById(R.id.txtConnectivity); txtBattery = (TextView) findViewById(R.id.txtBattery); txtLocation = (TextView) findViewById(R.id.txtLocation); // -- Create a link with services Intent ipIntent = new Intent(this, DeviceStatusServiceSameProcess.class); Intent opIntent = new Intent(this, DeviceStatusServiceDifferentProcess.class); bindService(ipIntent, inProcessServiceConnection, Context.BIND_AUTO_CREATE); bindService(opIntent, outProcessServiceConnection, Context.BIND_AUTO_CREATE); // Register the broadcast receiver to retrieve results of an out process service call IntentFilter intentFilter = new IntentFilter() ; intentFilter.addAction(IDeviceStatus.CONNECTIVITY_STATUS); intentFilter.addAction(IDeviceStatus.LOCATION_STATUS); this.registerReceiver(new ServiceReceiver(), intentFilter); } protected void onStop() { super.onStop(); // -- Unlink with services if (ipBoundToService) { unbindService(inProcessServiceConnection); } if (opBoundToService) { unbindService(outProcessServiceConnection); } } private ServiceConnection inProcessServiceConnection = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { ipBoundToService = false; } public void onServiceConnected(ComponentName name, IBinder service) { LocalBinder binder = (LocalBinder) service; targetIPService = (IDeviceStatus) binder.getService(); ipBoundToService = true; } }; private ServiceConnection outProcessServiceConnection = new ServiceConnection() { public void onServiceDisconnected(ComponentName name) { opBoundToService = false; } public void onServiceConnected(ComponentName name, IBinder service) { opBoundToService = true; targetOPService = new Messenger(service); } }; /* ************** * Button Listeners * ************** */ /** * Call an in-process service. Service consumer simply calls service API and can use * return value * * @param view */ public void onButtonRefreshUsingSameProcessClick(View view) { // If this service is available if (ipBoundToService) { // Connectivity List<ProviderStatus> connectivityProviderStatus = (List<ProviderStatus>) targetIPService.getConnectivityProvidersStatus(this.getClass().getPackage().getName()); boolean isInternetEnabled = targetIPService.isInternetConnectivityOn(this.getClass().getPackage().getName()); StringBuffer sbConnectivity = new StringBuffer(); sbConnectivity.append(updateConnectivity(isInternetEnabled, connectivityProviderStatus)); txtConnectivity.setText(sbConnectivity.toString()); // Battery IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); registerReceiver(new ServiceReceiver(), batteryLevelFilter); // Location List<ProviderStatus> locationProvidersStatus = (List<ProviderStatus>) targetIPService.getLocationProvidersStatus(this.getClass().getPackage().getName()); StringBuffer sbLocation = new StringBuffer(); sbLocation.append(updateLocation(locationProvidersStatus)); txtLocation.setText(sbLocation.toString()); } else { Toast.makeText(this, "No service connected.", Toast.LENGTH_SHORT); } } /** * Call an out-of-process service. Process involves: * 1. Select valid method signature * 2. Create message with corresponding index number * 3. Create a bundle (cf. http://developer.android.com/reference/android/os/Bundle.html) for restrictions on data types * 4. Add parameter values. The values are held in key-value pairs with the parameter name being the key * 5. Send message * * Currently no return value is returned. To do so would require a reverse binding process from the service, * i.e a callback interface and handler/messenger code in the consumer. The use of intents or even selective intents (define * an intent that can only be intercepted by a stated application) will achieve the same result with less binding. * @param view */ public void onButtonRefreshUsingDifferentProcessClick(View view) { // If this service is available if (opBoundToService) { // -- Connectivity //isInternetConnectivityOn // Name the out process method String targetMethod = "isInternetConnectivityOn(String callerPackageName)"; Message outMessage = Message.obtain(null, ServiceMethodTranslator.getMethodIndex(IDeviceStatus.methodsArray, targetMethod), 0, 0); // Fill parameters Bundle outBundle = new Bundle(); outBundle.putString(ServiceMethodTranslator.getMethodParameterName(targetMethod, 0), this.getClass().getPackage().getName()); outMessage.setData(outBundle); // Call the out process method try { targetOPService.send(outMessage); } catch (RemoteException e) { Toast.makeText(this, "No such method in this service.", Toast.LENGTH_SHORT); e.printStackTrace(); } // getConnectivityProvidersStatus // Name the out process method String nameGetConnectivityProvidersStatus = "getConnectivityProvidersStatus(String callerPackageName)"; Message getConnectivityProvidersStatus = Message.obtain(null, ServiceMethodTranslator.getMethodIndex(IDeviceStatus.methodsArray, nameGetConnectivityProvidersStatus), 0, 0); // Fill parameters Bundle getConnectivityProvidersStatusParams = new Bundle(); getConnectivityProvidersStatusParams.putString(ServiceMethodTranslator.getMethodParameterName(targetMethod, 0), this.getClass().getPackage().getName()); getConnectivityProvidersStatus.setData(getConnectivityProvidersStatusParams); // Call the out process method try { targetOPService.send(getConnectivityProvidersStatus); } catch (RemoteException e) { Toast.makeText(this, "No such method in this service.", Toast.LENGTH_SHORT); e.printStackTrace(); } // -- Battery IntentFilter batteryLevelFilter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED); registerReceiver(new ServiceReceiver(), batteryLevelFilter); // -- Location // getLocationProvidersStatus // Name the out process method String nameGetLocationProvidersStatus = "getLocationProvidersStatus(String callerPackageName)"; Message getLocationProvidersStatus = Message.obtain(null, ServiceMethodTranslator.getMethodIndex(IDeviceStatus.methodsArray, nameGetLocationProvidersStatus), 0, 0); // Fill parameters Bundle getLocationProvidersStatusParams = new Bundle(); getLocationProvidersStatusParams.putString(ServiceMethodTranslator.getMethodParameterName(targetMethod, 0), this.getClass().getPackage().getName()); getLocationProvidersStatus.setData(getLocationProvidersStatusParams); // Call the out process method try { targetOPService.send(getLocationProvidersStatus); } catch (RemoteException e) { Toast.makeText(this, "No such method in this service.", Toast.LENGTH_SHORT); e.printStackTrace(); } } else { Toast.makeText(this, "No service connected.", Toast.LENGTH_SHORT); } } /** * Utilities button to reset all values of this activity * @param view */ public void onButtonResetClick(View view) { txtConnectivity.setText("Nothing yet"); txtBattery.setText("Nothing yet"); txtLocation.setText("Nothing yet"); } /* ************** * Broadcast receiver * ************** */ /** * Broadcast receiver to receive intents from Service methods * * TODO: Intent Categories could be used to discriminate between * returned method intents rather than an intent per method * */ private class ServiceReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { Log.i(this.getClass().getSimpleName(), intent.getAction()); // Connectivity if (intent.getAction().equals(IDeviceStatus.CONNECTIVITY_STATUS)) { Log.i(this.getClass().getSimpleName(), "Out of process real service received intent - CONNECTIVITY"); boolean isInternetEnabled = false; List<ProviderStatus> connectivityProviders = new ArrayList<ProviderStatus>(); if(intent.hasExtra(IDeviceStatus.CONNECTIVITY_INTERNET_ON)) { isInternetEnabled = intent.getBooleanExtra(IDeviceStatus.CONNECTIVITY_INTERNET_ON, false); } if(intent.hasExtra(IDeviceStatus.CONNECTIVITY_PROVIDER_LIST)) { connectivityProviders = intent.getParcelableArrayListExtra(IDeviceStatus.CONNECTIVITY_PROVIDER_LIST); } StringBuffer sb = new StringBuffer(); sb.append(updateConnectivity(isInternetEnabled, connectivityProviders)); txtConnectivity.setText(sb.toString()); } // Location else if (intent.getAction().equals(IDeviceStatus.LOCATION_STATUS)) { Log.i(this.getClass().getSimpleName(), "Out of process real service received intent - LOCATION_STATUS"); List<ProviderStatus> locationProvidersStatus = intent.getParcelableArrayListExtra(IDeviceStatus.LOCATION_PROVIDER_LIST); StringBuffer sb = new StringBuffer(); sb.append(updateLocation(locationProvidersStatus)); txtLocation.setText(sb.toString()); } // Battery else if (intent.getAction().equals(Intent.ACTION_BATTERY_CHANGED)) { context.unregisterReceiver(this); double level = -1; double temperature = -1; double voltage = -1; int rawLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, -1); int scale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, -1); int rawTemperature = intent.getIntExtra(BatteryManager.EXTRA_TEMPERATURE, -1); int rawVoltage = intent.getIntExtra(BatteryManager.EXTRA_VOLTAGE, -1); int status = intent.getIntExtra(BatteryManager.EXTRA_STATUS, -1); int plugged = intent.getIntExtra(BatteryManager.EXTRA_PLUGGED, -1); if (rawLevel >= 0 && scale > 0) { level = (rawLevel * 100) / scale; } if (rawTemperature >= 0) { temperature = rawTemperature/10; } if (rawVoltage >= 0) { voltage = rawVoltage/1000; } BatteryStatus batteryStatus = new BatteryStatus(level, scale, voltage, temperature, status, plugged); Log.e(this.getClass().getSimpleName(), "Battery status > level: "+level+"% (="+rawLevel+"/"+scale+"), temperature: "+temperature+"°C (="+rawTemperature+"), voltage: "+voltage+"V (="+rawVoltage+"mV)"); txtBattery.setText(updateBattery(batteryStatus)); } } } public String updateConnectivity(boolean isInternetEnabled, List<ProviderStatus> connectivityProviders) { StringBuffer sb = new StringBuffer(); // -- Internet enabled? sb.append("** Internet is enabled? "+(isInternetEnabled ? "yes" : "no")+"\n"); // --- Providers for(ProviderStatus connectivityProvider : connectivityProviders) { sb.append("** "+connectivityProvider.getName()+": "+(connectivityProvider.isEnabled() ? "enabled" : "disabled")+"\n"); } return sb.toString(); } public String updateBattery(BatteryStatus batteryStatus) { StringBuffer sb = new StringBuffer(); sb.append("Remaining level: "+batteryStatus.getLevel()+"%\n" + "Temperature: "+batteryStatus.getTemperature()+"°C\n" + "Voltage: "+batteryStatus.getVoltage()+"V\n"+ "Status: "); switch(batteryStatus.getStatus()) { case BatteryManager.BATTERY_STATUS_CHARGING: sb.append("charging"); break; case BatteryManager.BATTERY_STATUS_DISCHARGING: sb.append("discharging"); break; case BatteryManager.BATTERY_STATUS_NOT_CHARGING: sb.append("not charging"); break; case BatteryManager.BATTERY_STATUS_FULL: sb.append("full"); break; default: sb.append("unknown"); } switch(batteryStatus.getPlugged()) { case BatteryManager.BATTERY_PLUGGED_AC: sb.append(", plugged on AC"); case BatteryManager.BATTERY_PLUGGED_USB: sb.append(", plugged on USB"); default: sb.append(", not plugged"); } sb.append("\n"); return sb.toString(); } public String updateLocation(List<ProviderStatus> locationProviderStatus) { StringBuffer sb = new StringBuffer(); sb.append("Providers:\n"); for (ProviderStatus providerStatus : locationProviderStatus) { sb.append("* "+providerStatus.getName()+" ["+(providerStatus.isEnabled() ? "enabled" : "disabled")+"]\n"); } // -- Add these data to the text return sb.toString(); } }