package net.screenfreeze.deskcon;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.KeyStore;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.X509Certificate;
import java.util.Calendar;
import java.util.Date;
import java.util.Random;
import org.spongycastle.jce.X509Principal;
import org.spongycastle.x509.X509V3CertificateGenerator;
import android.annotation.SuppressLint;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningServiceInfo;
import android.app.AlarmManager;
import android.app.AlertDialog;
import android.app.PendingIntent;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.AsyncTask;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.Preference.OnPreferenceClickListener;
import android.preference.PreferenceActivity;
import android.preference.PreferenceManager;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
@SuppressWarnings("deprecation")
public class MainActivity extends PreferenceActivity {
private static SharedPreferences sharedPrefs;
private static AlarmManager alarmManager;
private static PendingIntent statusUpdateServicePIntent;
private static Editor sharedPrefsEditor;
private static Intent statusUpdateServiceIntent;
private static Intent controlServiceIntent;
private static Intent discoveryServiceIntent;
@SuppressLint("CommitPrefEdits")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
sharedPrefs = PreferenceManager.getDefaultSharedPreferences(this);
sharedPrefsEditor = sharedPrefs.edit();
alarmManager = (AlarmManager)getSystemService(Context.ALARM_SERVICE);
statusUpdateServiceIntent = new Intent(this, StatusUpdateService.class);
statusUpdateServicePIntent = PendingIntent.getService(this, 0, statusUpdateServiceIntent, PendingIntent.FLAG_UPDATE_CURRENT);
controlServiceIntent = new Intent(this, ControlService.class);
discoveryServiceIntent = new Intent(this, DiscoveryService.class);
Preference desktophostsnewpref = findPreference("desktophosts");
Preference notificationaccesspref = findPreference("notification_access");
Preference notificationwhitelistpref = findPreference("notification_whitelist");
Preference firstrunpref = findPreference("firstrun");
Preference generatekeypref = findPreference("generatekeys");
Preference uuidpref = findPreference("uuid");
Preference aboutpref = findPreference("about");
Preference changelogpref = findPreference("changelog");
// hide from user
getPreferenceScreen().removePreference(firstrunpref);
getPreferenceScreen().removePreference(uuidpref);
desktophostsnewpref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent ha = new Intent(getApplicationContext(), DesktopHostsActivity.class);
startActivity(ha);
return false;
}
});
generatekeypref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showGenerateKeypairDialog();
return false;
}
});
aboutpref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showAboutDialog();
return false;
}
});
changelogpref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
showChangelogDialog();
return false;
}
});
notificationaccesspref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
// Because Notification Access only on API18 and up
int currentapiVersion = android.os.Build.VERSION.SDK_INT;
if (currentapiVersion >= 18){
// NotificationListener is still buggy
//Intent nai = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
Intent nai = new Intent("android.settings.ACCESSIBILITY_SETTINGS");
startActivity(nai);
} else{
Intent nai = new Intent("android.settings.ACCESSIBILITY_SETTINGS");
startActivity(nai);
}
return false;
}
});
notificationwhitelistpref.setOnPreferenceClickListener(new OnPreferenceClickListener() {
@Override
public boolean onPreferenceClick(Preference preference) {
Intent wa = new Intent(getApplicationContext(), NotificationWhitelistActivity.class);
startActivity(wa);
return false;
}
});
sharedPrefs.registerOnSharedPreferenceChangeListener(prefsChangeListener);
// start at firstrun
boolean isfirstrun = sharedPrefs.getBoolean("firstrun", true);
if (isfirstrun) {
onFirstrun();
}
else {
initServices();
}
}
private boolean isControlServiceRunning() {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (ControlService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
private void initServices() {
if (sharedPrefs.getBoolean("allow_control", true)) {
boolean cs_running = isControlServiceRunning();
if (!cs_running) {
startService(controlServiceIntent);
}
}
if (sharedPrefs.getBoolean("status_updates", true)) {
Log.d("Update Service: ", "update Alarm");
int min = Integer.parseInt(sharedPrefs.getString("status_update_interval", "40"));
Calendar cal = Calendar.getInstance();
int secs = min * 60;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
secs*1000, statusUpdateServicePIntent);
}
//startService(discoveryServiceIntent);
}
// Actions if a Preference changes
private OnSharedPreferenceChangeListener prefsChangeListener =
new OnSharedPreferenceChangeListener() {
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
// status_updates Preference
if (key.equals("status_updates")) {
boolean state = sharedPrefs.getBoolean(key, true);
if (state) {
// start update service
Log.d("Update Service: ", "start");
int min = Integer.parseInt(sharedPrefs.getString("status_update_interval", "40"));
Calendar cal = Calendar.getInstance();
int secs = min * 60;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
secs*1000, statusUpdateServicePIntent);
}
else {
// stop update service
alarmManager.cancel(statusUpdateServicePIntent);
Log.d("Update Service: ", "stop");
}
}
// status_update_interval Preference
if (key.equals("status_update_interval")) {
boolean state = sharedPrefs.getBoolean("status_updates", true);
// apply new interval
if (state) {
Log.d("Update Service: ", "restart");
alarmManager.cancel(statusUpdateServicePIntent);
// start update service
int min = Integer.parseInt(sharedPrefs.getString("status_update_interval", "40"));
Calendar cal = Calendar.getInstance();
int secs = min * 60;
alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
secs*1000, statusUpdateServicePIntent);
}
}
// allow_control Preference
else if (key.equals("allow_control")) {
boolean state = sharedPrefs.getBoolean(key, true);
if (state) {
// start control service
startService(controlServiceIntent);
}
else {
// stop control service
stopService(controlServiceIntent);
}
}
// allow_control Preference
else if (key.equals("control_port")) {
boolean state = sharedPrefs.getBoolean("allow_control", true);
//apply new port
if (state) {
stopService(controlServiceIntent);
// start control service
startService(controlServiceIntent);
}
}
}
};
private void onFirstrun() {
// set the UUID
TelephonyManager telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
String UUID = telephonyManager.getDeviceId();
// if no telephone uid, then generate random number
if (UUID == null || UUID.equals("")) {
Random rand = new Random();
long MAX = 999999999999999L;
long MIN = 100000000000000L;
long number = Math.abs(Long.valueOf(rand.nextLong()*(MAX - MIN)));
UUID = Long.toString(number);
}
// read default Notification Whitelist
InputStream is = this.getResources().openRawResource(R.raw.defaultnotificationwl);
byte[] b = null;
try {
b = new byte[is.available()];
is.read(b);
is.close();
} catch (IOException e) {
e.printStackTrace();
}
String notwl = new String(b);
sharedPrefsEditor.putString("notification_whitelist", notwl);
sharedPrefsEditor.putString("uuid", UUID);
sharedPrefsEditor.putBoolean("firstrun", false);
sharedPrefsEditor.commit();
// generate keypair
new KeypairgenerationTask().execute();
// start update service
// int min = Integer.parseInt(sharedPrefs.getString("status_update_interval", "40"));
// Calendar cal = Calendar.getInstance();
// int secs = min * 60;
// alarmManager.setRepeating(AlarmManager.RTC_WAKEUP, cal.getTimeInMillis(),
// secs*1000, statusUpdateServicePIntent);
}
private void showAboutDialog() {
LayoutInflater li = getLayoutInflater();
View aboutView = li.inflate(R.layout.about, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setView(aboutView);
alertDialogBuilder.setCancelable(true);
alertDialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
private void showChangelogDialog() {
LayoutInflater li = getLayoutInflater();
View aboutView = li.inflate(R.layout.changelog, null);
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setView(aboutView);
alertDialogBuilder.setTitle("Change log");
alertDialogBuilder.setCancelable(true);
alertDialogBuilder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
private void showGenerateKeypairDialog() {
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setTitle("Keypair");
alertDialogBuilder.setMessage("Do you really want to generate a new Keypair?\nEvery already paired Device, will be erased!");
alertDialogBuilder.setCancelable(true);
alertDialogBuilder.setPositiveButton("Yes", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
DesktopHostsDBHelper dbhelper = new DesktopHostsDBHelper(getApplicationContext());
dbhelper.clearDB();
new KeypairgenerationTask().execute();
dialog.cancel();
}
});
alertDialogBuilder.setNegativeButton("No", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.cancel();
}
});
AlertDialog alertDialog = alertDialogBuilder.create();
alertDialog.show();
}
private class KeypairgenerationTask extends AsyncTask<Void, Void, Void> {
private ProgressDialog progress = null;
@Override
protected Void doInBackground(Void... arg0) {
Log.d("Cert Gen: ", "begin to generate");
try {
// gen the RSA keypair
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA");
keyPairGenerator.initialize(2048, new SecureRandom());
KeyPair KPair = keyPairGenerator.generateKeyPair();
// generate Certificate
X509V3CertificateGenerator v3CertGen = new X509V3CertificateGenerator();
BigInteger serial = BigInteger.valueOf(new SecureRandom().nextInt());
String devicename = sharedPrefs.getString("device_name", "Device");
String deviceuuid = sharedPrefs.getString("uuid", "000000001111111");
v3CertGen.setSerialNumber(serial.abs());
v3CertGen.setIssuerDN(new X509Principal("CN=" + deviceuuid+"/" +devicename + ", OU=None, O=None L=None, C=None"));
v3CertGen.setNotBefore(new Date(System.currentTimeMillis() - 1000L * 60 * 60 * 24 * 30));
v3CertGen.setNotAfter(new Date(System.currentTimeMillis() + (1000L * 60 * 60 * 24 * 365*10)));
v3CertGen.setSubjectDN(new X509Principal("CN=" + deviceuuid+"/" +devicename + ", OU=None, O=None L=None, C=None"));
v3CertGen.setPublicKey(KPair.getPublic());
v3CertGen.setSignatureAlgorithm("SHA256WithRSAEncryption");
X509Certificate PKCertificate = v3CertGen.generate(KPair.getPrivate());
// create keystore
InputStream keyStoreStream = getResources().openRawResource(R.raw.defaultkeystore);
KeyStore MyKeyStore = KeyStore.getInstance("BKS");
MyKeyStore.load(keyStoreStream, "android".toCharArray());
Certificate[] certchain = new Certificate[1];
certchain[0] = PKCertificate;
PrivateKey privkey = KPair.getPrivate();
MyKeyStore.setKeyEntry("mykeypair",privkey, "passwd".toCharArray(), certchain);
// write new Keystore
OutputStream output = openFileOutput("devicekeystore.bks", Context.MODE_PRIVATE);
MyKeyStore.store(output, "android".toCharArray());
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
@Override
protected void onPostExecute(Void result) {
progress.dismiss();
Log.d("Cert Gen: ", "finished to generate");
initServices();
super.onPostExecute(result);
}
@Override
protected void onPreExecute() {
progress = ProgressDialog.show(MainActivity.this, null,
"Generating Encryption Keypair...");
super.onPreExecute();
}
@Override
protected void onProgressUpdate(Void... values) {
super.onProgressUpdate(values);
}
}
}