diff --git a/app/src/apkFlavor/AndroidManifest.xml b/app/src/apkFlavor/AndroidManifest.xml index 53d37d66..714c2b82 100644 --- a/app/src/apkFlavor/AndroidManifest.xml +++ b/app/src/apkFlavor/AndroidManifest.xml @@ -170,6 +170,7 @@ + diff --git a/app/src/fdroidFlavor/AndroidManifest.xml b/app/src/fdroidFlavor/AndroidManifest.xml index 0e7bb421..37fd4ca2 100644 --- a/app/src/fdroidFlavor/AndroidManifest.xml +++ b/app/src/fdroidFlavor/AndroidManifest.xml @@ -168,6 +168,7 @@ + diff --git a/app/src/googlePlayFlavor/AndroidManifest.xml b/app/src/googlePlayFlavor/AndroidManifest.xml index 175ef7e1..8c118b6c 100644 --- a/app/src/googlePlayFlavor/AndroidManifest.xml +++ b/app/src/googlePlayFlavor/AndroidManifest.xml @@ -155,6 +155,7 @@ + diff --git a/app/src/main/java/com/jens/automation2/ActivityManageRule.java b/app/src/main/java/com/jens/automation2/ActivityManageRule.java index 6fded02f..bc011f3b 100644 --- a/app/src/main/java/com/jens/automation2/ActivityManageRule.java +++ b/app/src/main/java/com/jens/automation2/ActivityManageRule.java @@ -131,6 +131,8 @@ public class ActivityManageRule extends Activity final static int requestCodeTriggerTetheringEdit = 818; final static int requestCodeActionWakeLockAdd = 819; final static int requestCodeActionWakeLockEdit = 820; + final static int requestCodeTriggerSubSystemStateAdd = 821; + final static int requestCodeTriggerSubSystemStateEdit = 822; public static ActivityManageRule getInstance() { @@ -321,6 +323,12 @@ public class ActivityManageRule extends Activity tetheringEditor.putExtra(intentNameTriggerParameter1, selectedTrigger.getTriggerParameter()); startActivityForResult(tetheringEditor, requestCodeTriggerTetheringEdit); break; + case subSystemState: + Intent subSystemStateEditor = new Intent(ActivityManageRule.this, ActivityManageTriggerSubSystemState.class); + subSystemStateEditor.putExtra(intentNameTriggerParameter1, selectedTrigger.getTriggerParameter()); + subSystemStateEditor.putExtra(intentNameTriggerParameter2, selectedTrigger.getTriggerParameter2()); + startActivityForResult(subSystemStateEditor, requestCodeTriggerSubSystemStateEdit); + break; default: break; } @@ -585,6 +593,8 @@ public class ActivityManageRule extends Activity items.add(new Item(typesLong[i].toString(), R.drawable.alarm)); else if(types[i].toString().equals(Trigger_Enum.tethering.toString())) items.add(new Item(typesLong[i].toString(), R.drawable.router)); + else if(types[i].toString().equals(Trigger_Enum.subSystemState.toString())) + items.add(new Item(typesLong[i].toString(), R.drawable.subsystemstate)); else items.add(new Item(typesLong[i].toString(), R.drawable.placeholder)); } @@ -757,19 +767,22 @@ public class ActivityManageRule extends Activity Miscellaneous.messageBox(getResources().getString(R.string.info), getResources().getString(R.string.lockedCommentScreenMustBeOff), ActivityManageRule.this).show(); return; } - else if(triggerType == Trigger_Enum.deviceStarts) + /*else if(triggerType == Trigger_Enum.deviceStarts) { newTrigger.setTriggerType(Trigger_Enum.deviceStarts); ruleToEdit.getTriggerSet().add(newTrigger); refreshTriggerList(); return; - } - else if(triggerType == Trigger_Enum.serviceStarts) + }*/ + else if(triggerType == Trigger_Enum.deviceStarts || triggerType == Trigger_Enum.serviceStarts) { - newTrigger.setTriggerType(Trigger_Enum.serviceStarts); - ruleToEdit.getTriggerSet().add(newTrigger); - refreshTriggerList(); - return; +// newTrigger.setTriggerType(Trigger_Enum.serviceStarts); +// ruleToEdit.getTriggerSet().add(newTrigger); + + booleanChoices = new String[]{getResources().getString(R.string.yes), getResources().getString(R.string.no)}; + +// refreshTriggerList(); +// return; } else if(triggerType == Trigger_Enum.headsetPlugged) booleanChoices = new String[]{getResources().getString(R.string.connected), getResources().getString(R.string.disconnected)}; @@ -793,6 +806,13 @@ public class ActivityManageRule extends Activity startActivityForResult(tetheringTriggerEditor, requestCodeTriggerTetheringAdd); return; } + else if(triggerType == Trigger_Enum.subSystemState) + { + newTrigger.setTriggerType(Trigger_Enum.subSystemState); + Intent subSystemStateTriggerEditor = new Intent(myContext, ActivityManageTriggerSubSystemState.class); + startActivityForResult(subSystemStateTriggerEditor, requestCodeTriggerSubSystemStateAdd); + return; + } else getTriggerParameterDialog(context, booleanChoices).show(); @@ -1853,6 +1873,17 @@ public class ActivityManageRule extends Activity this.refreshTriggerList(); } } + else if(requestCode == requestCodeTriggerSubSystemStateAdd) + { + if(resultCode == RESULT_OK) + { + newTrigger.setTriggerParameter(data.getBooleanExtra(intentNameTriggerParameter1, true)); + newTrigger.setTriggerParameter2(data.getStringExtra(intentNameTriggerParameter2)); + newTrigger.setParentRule(ruleToEdit); + ruleToEdit.getTriggerSet().add(newTrigger); + this.refreshTriggerList(); + } + } else if(requestCode == requestCodeTriggerTetheringEdit) { if(resultCode == RESULT_OK) @@ -1865,6 +1896,19 @@ public class ActivityManageRule extends Activity this.refreshTriggerList(); } } + else if(requestCode == requestCodeTriggerSubSystemStateEdit) + { + if(resultCode == RESULT_OK) + { + Trigger editedTrigger = new Trigger(); + editedTrigger.setTriggerType(Trigger_Enum.subSystemState); + editedTrigger.setTriggerParameter(data.getBooleanExtra(intentNameTriggerParameter1, true)); + editedTrigger.setTriggerParameter2(data.getStringExtra(intentNameTriggerParameter2)); + editedTrigger.setParentRule(ruleToEdit); + ruleToEdit.getTriggerSet().set(editIndex, editedTrigger); + this.refreshTriggerList(); + } + } } protected AlertDialog getActionTypeDialog() diff --git a/app/src/main/java/com/jens/automation2/ActivityManageTriggerSubSystemState.java b/app/src/main/java/com/jens/automation2/ActivityManageTriggerSubSystemState.java new file mode 100644 index 00000000..6c32db74 --- /dev/null +++ b/app/src/main/java/com/jens/automation2/ActivityManageTriggerSubSystemState.java @@ -0,0 +1,72 @@ +package com.jens.automation2; + +import android.app.Activity; +import android.content.Intent; +import android.os.Bundle; +import android.view.View; +import android.widget.Button; +import android.widget.RadioButton; + +import androidx.annotation.Nullable; + +import com.jens.automation2.Trigger.subSystemStates; + +public class ActivityManageTriggerSubSystemState extends Activity +{ + RadioButton rbSubSystemStateWifi, rbSubSystemStateBluetooth; + RadioButton rbSubSystemStateEnabled, rbSubSystemStateDisabled; + Button bSubSystemStateSave; + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) + { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_manage_trigger_subsystemstate); + + rbSubSystemStateWifi = (RadioButton)findViewById(R.id.rbSubSystemStateWifi); + rbSubSystemStateBluetooth = (RadioButton)findViewById(R.id.rbSubSystemStateBluetooth); + rbSubSystemStateEnabled = (RadioButton)findViewById(R.id.rbSubSystemStateEnabled); + rbSubSystemStateDisabled = (RadioButton)findViewById(R.id.rbSubSystemStateDisabled); + bSubSystemStateSave = (Button)findViewById(R.id.bSubSystemStateSave); + + if(getIntent().hasExtra(ActivityManageRule.intentNameTriggerParameter1) && getIntent().hasExtra(ActivityManageRule.intentNameTriggerParameter2)) + { + subSystemStates desiredState = subSystemStates.valueOf(getIntent().getStringExtra(ActivityManageRule.intentNameTriggerParameter2)); + + switch(desiredState) + { + case wifi: + rbSubSystemStateWifi.setChecked(true); + break; + case bluetooth: + rbSubSystemStateBluetooth.setChecked(true); + break; + default: + } + + if(getIntent().getBooleanExtra(ActivityManageRule.intentNameTriggerParameter1, true)) + rbSubSystemStateEnabled.setChecked(true); + else + rbSubSystemStateDisabled.setChecked(true); + } + + bSubSystemStateSave.setOnClickListener(new View.OnClickListener() + { + @Override + public void onClick(View view) + { + Intent data = new Intent(); + + data.putExtra(ActivityManageRule.intentNameTriggerParameter1, rbSubSystemStateEnabled.isChecked()); + + if(rbSubSystemStateWifi.isChecked()) + data.putExtra(ActivityManageRule.intentNameTriggerParameter2, subSystemStates.wifi.name()); + else if(rbSubSystemStateBluetooth.isChecked()) + data.putExtra(ActivityManageRule.intentNameTriggerParameter2, subSystemStates.bluetooth.name()); + + ActivityManageTriggerSubSystemState.this.setResult(RESULT_OK, data); + finish(); + } + }); + } +} diff --git a/app/src/main/java/com/jens/automation2/AutomationService.java b/app/src/main/java/com/jens/automation2/AutomationService.java index 2d5fc7fd..4b361f4d 100644 --- a/app/src/main/java/com/jens/automation2/AutomationService.java +++ b/app/src/main/java/com/jens/automation2/AutomationService.java @@ -473,6 +473,7 @@ public class AutomationService extends Service implements OnInitListener PackageReplacedReceiver.setHasServiceBeenRunning(false, this); centralInstance = null; + Settings.serviceStartDone = false; } protected static Builder createDefaultNotificationBuilderOld() diff --git a/app/src/main/java/com/jens/automation2/ReceiverCoordinator.java b/app/src/main/java/com/jens/automation2/ReceiverCoordinator.java index 23a1f77e..14468b3d 100644 --- a/app/src/main/java/com/jens/automation2/ReceiverCoordinator.java +++ b/app/src/main/java/com/jens/automation2/ReceiverCoordinator.java @@ -18,6 +18,7 @@ import com.jens.automation2.receivers.NoiseListener; import com.jens.automation2.receivers.PhoneStatusListener; import com.jens.automation2.receivers.ProcessListener; import com.jens.automation2.receivers.ScreenStateReceiver; +import com.jens.automation2.receivers.SubSystemStateReceiver; import com.jens.automation2.receivers.TetheringReceiver; import com.jens.automation2.receivers.TimeZoneListener; @@ -182,6 +183,9 @@ public class ReceiverCoordinator if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.tethering)) TetheringReceiver.getInstance().startListener(AutomationService.getInstance()); + if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.subSystemState)) + SubSystemStateReceiver.getInstance().startListener(AutomationService.getInstance()); + try { Class testClass = Class.forName(ActivityManageRule.activityDetectionClassPath); @@ -223,6 +227,7 @@ public class ReceiverCoordinator MediaPlayerListener.getInstance().stopListener(AutomationService.getInstance()); DeviceOrientationListener.getInstance().stopListener(AutomationService.getInstance()); TetheringReceiver.getInstance().stopListener(AutomationService.getInstance()); + SubSystemStateReceiver.getInstance().stopListener(AutomationService.getInstance()); try { @@ -440,6 +445,24 @@ public class ReceiverCoordinator } } + if(Rule.isAnyRuleUsing(Trigger.Trigger_Enum.subSystemState)) + { + if(!SubSystemStateReceiver.getInstance().isListenerRunning()) + { + Miscellaneous.logEvent("i", "SubSystemStateReceiver", "Starting SubSystemStateReceiver because used in a new/changed rule.", 4); +// if(DevicePositionListener.getInstance().haveAllPermission()) + TetheringReceiver.getInstance().startListener(AutomationService.getInstance()); + } + } + else + { + if(SubSystemStateReceiver.getInstance().isListenerRunning()) + { + Miscellaneous.logEvent("i", "SubSystemStateReceiver", "Shutting down SubSystemStateReceiver because not used in any rule.", 4); + SubSystemStateReceiver.getInstance().stopListener(AutomationService.getInstance()); + } + } + AutomationService.updateNotification(); } } diff --git a/app/src/main/java/com/jens/automation2/Trigger.java b/app/src/main/java/com/jens/automation2/Trigger.java index e8a55329..9d83ff73 100644 --- a/app/src/main/java/com/jens/automation2/Trigger.java +++ b/app/src/main/java/com/jens/automation2/Trigger.java @@ -1,7 +1,6 @@ package com.jens.automation2; import android.bluetooth.BluetoothDevice; -import android.content.BroadcastReceiver; import android.content.Context; import android.os.Build; import android.service.notification.StatusBarNotification; @@ -61,6 +60,7 @@ public class Trigger serviceStarts, broadcastReceived, tethering, + subSystemState, phoneCall; //phoneCall always needs to be at the very end because of Google's shitty so called privacy public String getFullName(Context context) @@ -117,12 +117,16 @@ public class Trigger return context.getResources().getString(R.string.broadcastReceivedTitle); case tethering: return context.getResources().getString(R.string.tetheringState); + case subSystemState: + return context.getResources().getString(R.string.subSystemState); default: return "Unknown"; } } }; + public static enum subSystemStates { wifi, bluetooth }; + Rule parentRule = null; Calendar lastTimeNotApplied = null; @@ -236,6 +240,10 @@ public class Trigger if(!checkTetheringActive()) result = false; break; + case subSystemState: + if(!checkSubSystemState()) + result = false; + break; default: break; } @@ -408,7 +416,9 @@ public class Trigger boolean checkServiceStarts() { - return !Settings.serviceStartDone; +boolean result = !Settings.serviceStartDone == getTriggerParameter(); + return !Settings.serviceStartDone == getTriggerParameter(); +// return !Settings.serviceStartDone; } boolean checkProfileActive() @@ -536,6 +546,31 @@ public class Trigger return true; } + boolean checkSubSystemState() + { + try + { + subSystemStates state = subSystemStates.valueOf(triggerParameter2); + + switch (state) + { + case wifi: + return WifiBroadcastReceiver.isWifiEnabled(Miscellaneous.getAnyContext()) == triggerParameter; + case bluetooth: + return BluetoothReceiver.isBluetoothEnabled() == triggerParameter; + default: + Miscellaneous.logEvent("w", "checkSubSystemState()", "Invalid subSystemState: " + state.name(), 3); + return false; + } + } + catch(Exception e) + { + Miscellaneous.logEvent("e", "checkSubSystemState()", Log.getStackTraceString(e), 1); + } + + return false; + } + boolean checkBluetooth() { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format("Checking for bluetooth...", this.getParentRule().getName()), 4); @@ -812,7 +847,10 @@ public class Trigger } else { - if(BatteryReceiver.getBatteryLevel() >= this.getBatteryLevel()) + if(BatteryReceiver.getBatteryLevel() < 100 && BatteryReceiver.getBatteryLevel() >= this.getBatteryLevel() + || + BatteryReceiver.getBatteryLevel() > this.getBatteryLevel() + ) { Miscellaneous.logEvent("i", Miscellaneous.getAnyContext().getResources().getString(R.string.ruleCheckOf), String.format(Miscellaneous.getAnyContext().getResources().getString(R.string.ruleDoesntApplyBatteryHigherThan) + " " + String.valueOf(this.getBatteryLevel()), this.getParentRule().getName()), 3); return false; @@ -1642,11 +1680,11 @@ public class Trigger break; case deviceStarts: // This type doesn't have an activate/deactivate equivalent - returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.deviceHasJustStarted)); + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.deviceIsStarting) + ": " + String.valueOf(triggerParameter)); break; case serviceStarts: // This type doesn't have an activate/deactivate equivalent - returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.serviceHasJustStarted)); + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.serviceIsStarting) + ": " + String.valueOf(triggerParameter)); break; case broadcastReceived: if(triggerParameter) @@ -1662,6 +1700,25 @@ public class Trigger else returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.tetheringNotActive)); break; + case subSystemState: + Trigger.subSystemStates desiredState = subSystemStates.valueOf(triggerParameter2); + switch(desiredState) + { + case wifi: + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.wifi)); + break; + case bluetooth: + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.bluetooth)); + break; + } + + returnString.append(" " + Miscellaneous.getAnyContext().getResources().getString(R.string.is) + " "); + + if(triggerParameter) + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.activated)); + else + returnString.append(Miscellaneous.getAnyContext().getResources().getString(R.string.deactivated)); + break; default: returnString.append("error"); break; diff --git a/app/src/main/java/com/jens/automation2/receivers/BluetoothReceiver.java b/app/src/main/java/com/jens/automation2/receivers/BluetoothReceiver.java index 449bc60b..4c34660d 100644 --- a/app/src/main/java/com/jens/automation2/receivers/BluetoothReceiver.java +++ b/app/src/main/java/com/jens/automation2/receivers/BluetoothReceiver.java @@ -300,4 +300,16 @@ public class BluetoothReceiver extends BroadcastReceiver implements AutomationLi { return new Trigger_Enum[] { Trigger_Enum.bluetoothConnection }; } -} + + /** + * Check for Bluetooth. + * + * @return true if Bluetooth is available. + */ + public static boolean isBluetoothEnabled() + { + final BluetoothAdapter bluetoothAdapter = BluetoothAdapter.getDefaultAdapter(); + + return bluetoothAdapter != null && bluetoothAdapter.isEnabled() && bluetoothAdapter.getState() == BluetoothAdapter.STATE_ON; + } +} \ No newline at end of file diff --git a/app/src/main/java/com/jens/automation2/receivers/SubSystemStateReceiver.java b/app/src/main/java/com/jens/automation2/receivers/SubSystemStateReceiver.java new file mode 100644 index 00000000..7a382e32 --- /dev/null +++ b/app/src/main/java/com/jens/automation2/receivers/SubSystemStateReceiver.java @@ -0,0 +1,151 @@ +package com.jens.automation2.receivers; + +import android.bluetooth.BluetoothAdapter; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.net.wifi.WifiManager; + +import com.jens.automation2.AutomationService; +import com.jens.automation2.Miscellaneous; +import com.jens.automation2.Rule; +import com.jens.automation2.Trigger; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class SubSystemStateReceiver extends BroadcastReceiver implements AutomationListenerInterface +{ + public static AutomationService automationServiceRef = null; + private static IntentFilter subSystemStateIntentFilter = null; + private static BroadcastReceiver subSystemStateReceiverInstance = null; + private static Intent subSystemStatusIntent = null; + private static boolean subSystemStateReceiverActive = false; + static SubSystemStateReceiver instance; + + final static String stateBluetooth = "android.bluetooth.adapter.action.STATE_CHANGED"; + final static String stateWifi = "android.net.wifi.STATE_CHANGE"; + final static String connectivityBroadcast = "android.net.conn.CONNECTIVITY_CHANGE"; + + static Map stateMap = null; + + @Override + public void onReceive(Context context, Intent intent) + { + if (intent == null) + return; + if (context == null) + return; + + Miscellaneous.logEvent("e", "ScreenStateReceiver", "Received: " + intent.getAction(), 3); + + if(stateMap == null) + stateMap = new HashMap<>(); + + try + { + /*if (intent.getAction().equals(stateWifi) || intent.getAction().equals(connectivityBroadcast)) + { + if(intent.hasExtra(WifiManager.EXTRA_WIFI_STATE)) + { + int wifiState = intent.getIntExtra(WifiManager.EXTRA_WIFI_STATE, WifiManager.WIFI_STATE_UNKNOWN); + + if (wifiState == WifiManager.WIFI_STATE_ENABLED) + stateMap.put("wifi", true); + else if (wifiState == WifiManager.WIFI_STATE_DISABLED) + stateMap.put("wifi", false); + } + } + else if (intent.getAction().equals(stateBluetooth)) + { + if(intent.hasExtra(BluetoothAdapter.EXTRA_STATE)) + { + int bluetoothState = intent.getIntExtra(BluetoothAdapter.EXTRA_STATE, BluetoothAdapter.ERROR); + + if (bluetoothState == BluetoothAdapter.STATE_ON) + stateMap.put("bluetooth", true); + else if (bluetoothState == BluetoothAdapter.STATE_OFF) + stateMap.put("bluetooth", false); + } + }*/ + if (intent.getAction().equals(stateWifi) || intent.getAction().equals(connectivityBroadcast) || intent.getAction().equals(stateBluetooth)) + { + ArrayList ruleCandidates = Rule.findRuleCandidates(Trigger.Trigger_Enum.subSystemState); + for (int i = 0; i < ruleCandidates.size(); i++) + { + if (ruleCandidates.get(i).getsGreenLight(context)) + ruleCandidates.get(i).activate(automationServiceRef, false); + } + } + else + { + Miscellaneous.logEvent("e", "SubSystemStateReceiver", "Unknown state received: " + intent.getAction(), 3); + } + } + catch (Exception e) + { + Miscellaneous.logEvent("e", "SubSystemStateReceiver", "Error receiving screen state: " + e.getMessage(), 3); + } + } + + public static SubSystemStateReceiver getInstance() + { + if(instance == null) + instance = new SubSystemStateReceiver(); + + return instance; + } + + @Override + public void startListener(AutomationService automationService) + { + if (!subSystemStateReceiverActive) + { + automationServiceRef = automationService; + + if (subSystemStateReceiverInstance == null) + subSystemStateReceiverInstance = new SubSystemStateReceiver(); + + if (subSystemStateIntentFilter == null) + { + subSystemStateIntentFilter = new IntentFilter(); + subSystemStateIntentFilter.addAction(stateWifi); + subSystemStateIntentFilter.addAction(connectivityBroadcast); + subSystemStateIntentFilter.addAction(stateBluetooth); + } + + subSystemStatusIntent = automationServiceRef.registerReceiver(subSystemStateReceiverInstance, subSystemStateIntentFilter); + + subSystemStateReceiverActive = true; + } + } + + @Override + public void stopListener(AutomationService automationService) + { + if (subSystemStateReceiverActive) + { + if (subSystemStateReceiverInstance != null) + { + automationServiceRef.unregisterReceiver(subSystemStateReceiverInstance); + subSystemStateReceiverInstance = null; + } + + subSystemStateReceiverActive = false; + } + } + + @Override + public boolean isListenerRunning() + { + return subSystemStateReceiverActive; + } + + @Override + public Trigger.Trigger_Enum[] getMonitoredTrigger() + { + return new Trigger.Trigger_Enum[]{Trigger.Trigger_Enum.subSystemState}; + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-hdpi/subsystemstate.png b/app/src/main/res/drawable-hdpi/subsystemstate.png new file mode 100644 index 00000000..96c18607 Binary files /dev/null and b/app/src/main/res/drawable-hdpi/subsystemstate.png differ diff --git a/app/src/main/res/layout/activity_manage_trigger_subsystemstate.xml b/app/src/main/res/layout/activity_manage_trigger_subsystemstate.xml new file mode 100644 index 00000000..193fd87f --- /dev/null +++ b/app/src/main/res/layout/activity_manage_trigger_subsystemstate.xml @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +