package eu.musesproject.client.contextmonitoring.sensors;
/*
* #%L
* musesclient
* %%
* Copyright (C) 2013 - 2014 HITEC
* %%
* 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.
* #L%
*/
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.os.AsyncTask;
import android.util.Log;
import eu.musesproject.client.contextmonitoring.ContextListener;
import eu.musesproject.client.db.entity.SensorConfiguration;
import eu.musesproject.contextmodel.ContextEvent;
import eu.musesproject.contextmodel.PackageStatus;
import java.util.ArrayList;
import java.util.List;
/**
* @author christophstanik
*
* Class to collect information about app installation status of the device.
* The class collects information about:
* - new app installed
* - already installed app updated
* - app deleted
* - list of all installed apps
*/
public class PackageSensor implements ISensor {
private static final String TAG = PackageSensor.class.getSimpleName();
// sensor identifier
public static final String TYPE = "CONTEXT_SENSOR_PACKAGE";
private static final String INITIAL_STARTUP = "";
// context property keys
public static final String PROPERTY_KEY_ID = "id";
public static final String PROPERTY_KEY_PACKAGE_STATUS = "packagestatus";
public static final String PROPERTY_KEY_PACKAGE_NAME = "packagename";
public static final String PROPERTY_KEY_APP_NAME = "appname";
public static final String PROPERTY_KEY_APP_VERSION = "appversion";
public static final String PROPERTY_KEY_INSTALLED_APPS = "installedapps";
private boolean sensorEnabled;
private Context context;
private ContextListener listener;
// stores the context events before the latest at position 0 and the latest at position 1
private List<ContextEvent> contextEventHistory;
// broadcast receiver fields
final PackageBroadcastReceiver packageReceiver = new PackageBroadcastReceiver();
private IntentFilter filter;
private boolean initialContextEventFired;
public PackageSensor(Context context) {
this.context = context;
init();
}
private void init() {
sensorEnabled = false;
contextEventHistory = new ArrayList<ContextEvent>(CONTEXT_EVENT_HISTORY_SIZE);
initialContextEventFired = false;
filter = new IntentFilter();
}
private void createInitialContextEvent() {
// create a list of installed ups and hold it
if(!initialContextEventFired) {
String[] params = new String[4];
params[0] = INITIAL_STARTUP;
params[1] = INITIAL_STARTUP;
params[2] = INITIAL_STARTUP;
params[3] = "-1";
new CreateContextEventAsync().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
initialContextEventFired = true;
}
}
@Override
public void enable() {
if(!sensorEnabled) {
Log.d(TAG, "start package sensor");
sensorEnabled = true;
registerPackageBroadcastReceiver();
createInitialContextEvent();
}
}
@Override
public void disable() {
if(sensorEnabled) {
Log.d(TAG, "stop package sensor");
sensorEnabled = false;
unregisterPackageBroadcastReceiver();
}
}
@Override
public void addContextListener(ContextListener listener) {
this.listener = listener;
}
@Override
public void removeContextListener(ContextListener listener) {
this.listener = listener;
}
@Override
public ContextEvent getLastFiredContextEvent() {
if(contextEventHistory.size() > 0) {
return contextEventHistory.get(contextEventHistory.size() - 1);
}
else {
return null;
}
}
private void createContextEvent(String packageStatus, String packageName, String appName, String appVersion) {
ContextEvent contextEvent = new ContextEvent();
contextEvent.setType(TYPE);
contextEvent.setTimestamp(System.currentTimeMillis());
contextEvent.addProperty(PROPERTY_KEY_PACKAGE_STATUS, packageStatus);
contextEvent.addProperty(PROPERTY_KEY_PACKAGE_NAME, packageName);
contextEvent.addProperty(PROPERTY_KEY_APP_NAME, appName);
contextEvent.addProperty(PROPERTY_KEY_APP_VERSION, appVersion);
contextEvent.addProperty(PROPERTY_KEY_INSTALLED_APPS, getInstalledApps());
contextEvent.generateId();
// add context event to the context event history
contextEventHistory.add(contextEvent);
if(contextEventHistory.size() > CONTEXT_EVENT_HISTORY_SIZE) {
contextEventHistory.remove(0);
}
if(listener != null) {
listener.onEvent(contextEvent);
}
}
private void registerPackageBroadcastReceiver() {
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addDataScheme("package");
context.registerReceiver(packageReceiver, filter);
}
private String getInstalledApps() {
String installedAppsFormatted = "";
PackageManager packageManager = context.getPackageManager();
List<ApplicationInfo> installedApps = packageManager.getInstalledApplications(PackageManager.GET_META_DATA);
for(ApplicationInfo appInfo : installedApps) {
String appName = appInfo.loadLabel(packageManager).toString();
String packageName = appInfo.packageName;
String appVersion;
try {
appVersion = String.valueOf(packageManager.getPackageInfo(packageName, 0).versionCode);
} catch (NameNotFoundException e) {
appVersion = "- 1";
}
installedAppsFormatted += appName + "," + packageName + "," + appVersion;
installedAppsFormatted += ";";
}
// remove last separation item
installedAppsFormatted = installedAppsFormatted.subSequence(0, installedAppsFormatted.length() - 1).toString();
return installedAppsFormatted;
}
private void unregisterPackageBroadcastReceiver() {
try {
context.unregisterReceiver(packageReceiver);
}
catch(IllegalArgumentException e) {
Log.d(TAG, "package receiver is already unregistered");
}
}
public class PackageBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (intent != null) {
// retrieve the package name
Uri uri = intent.getData();
String packageName = uri != null ? uri.getSchemeSpecificPart() : "unknown";
// procedure to retrieve the application name
PackageManager pm = context.getPackageManager();
ApplicationInfo ai;
try {
ai = pm.getApplicationInfo(packageName, 0);
} catch (final NameNotFoundException e) {
ai = null;
}
String appName = (String) (ai != null ? pm.getApplicationLabel(ai) : "unknown");
// procedure to retrieve the version code of the application
String appVersion;
try {
appVersion = String.valueOf(pm.getPackageInfo(packageName, 0).versionCode);
} catch (NameNotFoundException e) {
appVersion = "- 1";
}
// identify the package status
final String action = intent.getAction();
PackageStatus packageStatus = null;
if (action.equals(Intent.ACTION_PACKAGE_ADDED)) {
packageStatus = PackageStatus.INSTALLED;
} else if (action.equals(Intent.ACTION_PACKAGE_REMOVED)) {
packageStatus = PackageStatus.REMOVED;
} else if (action.equals(Intent.ACTION_PACKAGE_REPLACED)) {
packageStatus = PackageStatus.UPDATED;
}
String packageStatusName = packageStatus != null ? packageStatus.toString() : "unknown";
// prepare the context event creation
String[] params = new String[4];
params[0] = packageStatusName;
params[1] = packageName;
params[2] = appName;
params[3] = appVersion;
new CreateContextEventAsync().executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, params);
}
}
}
private class CreateContextEventAsync extends AsyncTask<String, Void, Void> {
@Override
protected Void doInBackground(String... params) {
if (sensorEnabled) {
if(params.length == 4) {
createContextEvent(params[0], params[1], params[2], params[3]);
}
}
return null;
}
}
@Override
public void configure(List<SensorConfiguration> config) {
// TODO Auto-generated method stub
}
@Override
public String getSensorType() {
return TYPE;
}
}