diff --git a/app/src/androidTest/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationDataTest.java b/app/src/androidTest/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationDataTest.java new file mode 100644 index 00000000..5a5e74a6 --- /dev/null +++ b/app/src/androidTest/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationDataTest.java @@ -0,0 +1,21 @@ +package ryey.easer.plugins.operation.launch_app; + +import android.os.Parcel; + +import org.junit.Test; + +import ryey.easer.plugins.TestHelper; + +import static org.junit.Assert.assertEquals; + +public class LaunchAppOperationDataTest { + + @Test + public void testParcel() { + LaunchAppOperationData dummyData = new LaunchAppOperationDataFactory().dummyData(); + Parcel parcel = TestHelper.writeToParcel(dummyData); + LaunchAppOperationData parceledData = LaunchAppOperationData.CREATOR.createFromParcel(parcel); + assertEquals(dummyData, parceledData); + } + +} \ No newline at end of file diff --git a/app/src/main/java/ryey/easer/plugins/PluginRegistry.java b/app/src/main/java/ryey/easer/plugins/PluginRegistry.java index fa0438c7..7f27f492 100644 --- a/app/src/main/java/ryey/easer/plugins/PluginRegistry.java +++ b/app/src/main/java/ryey/easer/plugins/PluginRegistry.java @@ -60,6 +60,7 @@ import ryey.easer.plugins.operation.command.CommandOperationPlugin; import ryey.easer.plugins.operation.event_control.EventControlOperationPlugin; import ryey.easer.plugins.operation.hotspot.HotspotOperationPlugin; +import ryey.easer.plugins.operation.launch_app.LaunchAppOperationPlugin; import ryey.easer.plugins.operation.media_control.MediaControlOperationPlugin; import ryey.easer.plugins.operation.network_transmission.NetworkTransmissionOperationPlugin; import ryey.easer.plugins.operation.ringer_mode.RingerModeOperationPlugin; @@ -122,6 +123,7 @@ final public class PluginRegistry { operation().registerPlugin(AlarmOperationPlugin.class); operation().registerPlugin(EventControlOperationPlugin.class); operation().registerPlugin(VolumeOperationPlugin.class); + operation().registerPlugin(LaunchAppOperationPlugin.class); //TODO: write more plugins } diff --git a/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppLoader.java b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppLoader.java new file mode 100644 index 00000000..0cac0619 --- /dev/null +++ b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppLoader.java @@ -0,0 +1,25 @@ +package ryey.easer.plugins.operation.launch_app; + +import android.content.Context; +import android.content.Intent; +import android.support.annotation.NonNull; + +import ryey.easer.commons.plugindef.ValidData; +import ryey.easer.commons.plugindef.operationplugin.OperationLoader; + +public class LaunchAppLoader extends OperationLoader { + LaunchAppLoader(Context context) { + super(context); + } + + @Override + public boolean load(@ValidData @NonNull LaunchAppOperationData data) { + Intent intent = context.getPackageManager().getLaunchIntentForPackage(data.app_package); + if (intent != null) { + intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); + context.startActivity(intent); + return true; + } + return false; + } +} diff --git a/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationData.java b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationData.java new file mode 100644 index 00000000..36c31bc3 --- /dev/null +++ b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationData.java @@ -0,0 +1,94 @@ +package ryey.easer.plugins.operation.launch_app; + +import android.os.Parcel; +import android.support.annotation.NonNull; + +import org.json.JSONException; +import org.json.JSONObject; + +import ryey.easer.Utils; +import ryey.easer.commons.C; +import ryey.easer.commons.IllegalStorageDataException; +import ryey.easer.commons.plugindef.operationplugin.OperationData; + +public class LaunchAppOperationData implements OperationData { + private static final String K_APP_PACKAGE = "package"; + + final String app_package; + + LaunchAppOperationData(String app_package) { + this.app_package = app_package; + } + + LaunchAppOperationData(@NonNull String data, @NonNull C.Format format, int version) throws IllegalStorageDataException { + switch (format) { + default: + try { + JSONObject jsonObject = new JSONObject(data); + app_package = jsonObject.getString(K_APP_PACKAGE); + } catch (JSONException e) { + throw new IllegalStorageDataException(e); + } + } + } + + @NonNull + @Override + public String serialize(@NonNull C.Format format) { + String ret; + switch (format) { + default: + try { + JSONObject jsonObject = new JSONObject(); + jsonObject.put(K_APP_PACKAGE, app_package); + ret = jsonObject.toString(); + } catch (JSONException e) { + throw new IllegalStateException(e); + } + } + return ret; + } + + @SuppressWarnings({"SimplifiableIfStatement", "RedundantIfStatement"}) + @Override + public boolean isValid() { + return app_package != null && !Utils.isBlank(app_package); + } + + @SuppressWarnings({"SimplifiableIfStatement", "RedundantIfStatement"}) + @Override + public boolean equals(Object obj) { + if (obj == this) + return true; + if (obj == null || !(obj instanceof LaunchAppOperationData)) + return false; + if (!Utils.nullableEqual(app_package, ((LaunchAppOperationData) obj).app_package)) + return false; + return true; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(app_package); + } + + public static final Creator CREATOR + = new Creator() { + public LaunchAppOperationData createFromParcel(Parcel in) { + return new LaunchAppOperationData(in); + } + + public LaunchAppOperationData[] newArray(int size) { + return new LaunchAppOperationData[size]; + } + }; + + private LaunchAppOperationData(Parcel in) { + app_package = in.readString(); + } +} diff --git a/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationDataFactory.java b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationDataFactory.java new file mode 100644 index 00000000..73387330 --- /dev/null +++ b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationDataFactory.java @@ -0,0 +1,30 @@ +package ryey.easer.plugins.operation.launch_app; + +import android.support.annotation.NonNull; + +import ryey.easer.commons.C; +import ryey.easer.commons.IllegalStorageDataException; +import ryey.easer.commons.plugindef.ValidData; +import ryey.easer.commons.plugindef.operationplugin.OperationDataFactory; + +class LaunchAppOperationDataFactory implements OperationDataFactory { + @NonNull + @Override + public Class dataClass() { + return LaunchAppOperationData.class; + } + + @ValidData + @NonNull + @Override + public LaunchAppOperationData dummyData() { + return new LaunchAppOperationData("com.dummy.app.package"); + } + + @ValidData + @NonNull + @Override + public LaunchAppOperationData parse(@NonNull String data, @NonNull C.Format format, int version) throws IllegalStorageDataException { + return new LaunchAppOperationData(data, format, version); + } +} diff --git a/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationPlugin.java b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationPlugin.java new file mode 100644 index 00000000..c46d91c4 --- /dev/null +++ b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppOperationPlugin.java @@ -0,0 +1,71 @@ +package ryey.easer.plugins.operation.launch_app; + +import android.app.Activity; +import android.content.Context; +import android.support.annotation.NonNull; + +import ryey.easer.R; +import ryey.easer.commons.plugindef.PluginViewFragment; +import ryey.easer.commons.plugindef.operationplugin.OperationDataFactory; +import ryey.easer.commons.plugindef.operationplugin.OperationLoader; +import ryey.easer.commons.plugindef.operationplugin.OperationPlugin; +import ryey.easer.commons.plugindef.operationplugin.PrivilegeUsage; + +public class LaunchAppOperationPlugin implements OperationPlugin { + + @NonNull + @Override + public String id() { + return "launch_app"; + } + + @Override + public int name() { + return R.string.op_launch_app; + } + + @Override + public boolean isCompatible(@NonNull final Context context) { + return true; + } + + @NonNull + @Override + public PrivilegeUsage privilege() { + return PrivilegeUsage.no_root; + } + + @Override + public int maxExistence() { + return 0; + } + + @Override + public boolean checkPermissions(@NonNull Context context) { + return true; + } + + @Override + public void requestPermissions(@NonNull Activity activity, int requestCode) { + } + + @NonNull + @Override + public OperationDataFactory dataFactory() { + return new LaunchAppOperationDataFactory(); + + } + + @NonNull + @Override + public PluginViewFragment view() { + return new LaunchAppPluginViewFragment(); + } + + @NonNull + @Override + public OperationLoader loader(@NonNull Context context) { + return new LaunchAppLoader(context); + } + +} diff --git a/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppPluginViewFragment.java b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppPluginViewFragment.java new file mode 100644 index 00000000..9666d096 --- /dev/null +++ b/app/src/main/java/ryey/easer/plugins/operation/launch_app/LaunchAppPluginViewFragment.java @@ -0,0 +1,38 @@ +package ryey.easer.plugins.operation.launch_app; + +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.EditText; + +import ryey.easer.R; +import ryey.easer.commons.plugindef.InvalidDataInputException; +import ryey.easer.commons.plugindef.PluginViewFragment; +import ryey.easer.commons.plugindef.ValidData; + +public class LaunchAppPluginViewFragment extends PluginViewFragment { + EditText et_app_package; + + @NonNull + @Override + public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) { + View view = inflater.inflate(R.layout.plugin_operation__launch_app, container, false); + et_app_package = view.findViewById(R.id.editText_app_package); + return view; + } + + @Override + protected void _fill(@ValidData @NonNull LaunchAppOperationData data) { + et_app_package.setText(data.app_package); + } + + @ValidData + @NonNull + @Override + public LaunchAppOperationData getData() throws InvalidDataInputException { + return new LaunchAppOperationData(et_app_package.getText().toString()); + } +} diff --git a/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOpeartionPluginViewFragment.java b/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOpeartionPluginViewFragment.java index 3b62c54c..0b055886 100644 --- a/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOpeartionPluginViewFragment.java +++ b/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOpeartionPluginViewFragment.java @@ -40,8 +40,10 @@ public class VolumeOpeartionPluginViewFragment extends PluginViewFragment { - CheckBox checkBox_ring, checkBox_media, checkBox_alarm, checkBox_notification; - SeekBar seekBar_ring, seekBar_media, seekBar_alarm, seekBar_notification; + private static final int STREAM_BLUETOOTH = 6; + + CheckBox checkBox_ring, checkBox_media, checkBox_alarm, checkBox_notification, checkBox_bt; + SeekBar seekBar_ring, seekBar_media, seekBar_alarm, seekBar_notification, seekBar_bt; @NonNull @Override @@ -95,6 +97,16 @@ public void onCheckedChanged(CompoundButton compoundButton, boolean b) { } }); + seekBar_bt = view.findViewById(R.id.seekBar_bt); + seekBar_bt.setMax(audioManager.getStreamMaxVolume(STREAM_BLUETOOTH)); + checkBox_bt = view.findViewById(R.id.checkBox_bt); + checkBox_bt.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton compoundButton, boolean b) { + seekBar_bt.setVisibility(b? View.VISIBLE : View.GONE); + } + }); + return view; } @@ -104,6 +116,7 @@ protected void _fill(@ValidData @NonNull VolumeOperationData data) { setVolumeVisual(checkBox_media, seekBar_media, data.vol_media); setVolumeVisual(checkBox_alarm, seekBar_alarm, data.vol_alarm); setVolumeVisual(checkBox_notification, seekBar_notification, data.vol_notification); + setVolumeVisual(checkBox_bt, seekBar_bt, data.vol_bt); } @ValidData @@ -114,7 +127,8 @@ public VolumeOperationData getData() throws InvalidDataInputException { Integer vol_media = getVolume(seekBar_media); Integer vol_alarm = getVolume(seekBar_alarm); Integer vol_notification = getVolume(seekBar_notification); - return new VolumeOperationData(vol_ring, vol_media, vol_alarm, vol_notification); + Integer vol_bt = getVolume(seekBar_bt); + return new VolumeOperationData(vol_ring, vol_media, vol_alarm, vol_notification, vol_bt); } private static void setVolumeVisual(CheckBox checkBox, SeekBar seekBar, Integer value) { diff --git a/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationData.java b/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationData.java index b400259b..6c50a442 100644 --- a/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationData.java +++ b/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationData.java @@ -36,17 +36,20 @@ public class VolumeOperationData implements OperationData { private static final String K_VOL_MEDIA = "media"; private static final String K_VOL_ALARM = "alarm"; private static final String K_VOL_NOTIFICATION = "notification"; + private static final String K_VOL_BT = "bluetooth"; Integer vol_ring; Integer vol_media; Integer vol_alarm; Integer vol_notification; + Integer vol_bt; - public VolumeOperationData(Integer vol_ring, Integer vol_media, Integer vol_alarm, Integer vol_notification) { + public VolumeOperationData(Integer vol_ring, Integer vol_media, Integer vol_alarm, Integer vol_notification, Integer vol_bt) { this.vol_ring = vol_ring; this.vol_media = vol_media; this.vol_alarm = vol_alarm; this.vol_notification = vol_notification; + this.vol_bt = vol_bt; } VolumeOperationData(@NonNull String data, @NonNull C.Format format, int version) throws IllegalStorageDataException { @@ -74,6 +77,7 @@ public void parse(@NonNull String data, @NonNull C.Format format, int version) t vol_media = optInteger(jsonObject, K_VOL_MEDIA); vol_alarm = optInteger(jsonObject, K_VOL_ALARM); vol_notification = optInteger(jsonObject, K_VOL_NOTIFICATION); + vol_bt = optInteger(jsonObject, K_VOL_BT); } catch (JSONException e) { throw new IllegalStorageDataException(e); } @@ -92,6 +96,7 @@ public String serialize(@NonNull C.Format format) { writeNonNull(jsonObject, vol_media, K_VOL_MEDIA); writeNonNull(jsonObject, vol_alarm, K_VOL_ALARM); writeNonNull(jsonObject, vol_notification, K_VOL_NOTIFICATION); + writeNonNull(jsonObject, vol_bt, K_VOL_BT); res = jsonObject.toString(); } catch (JSONException e) { throw new IllegalStateException(e); @@ -114,6 +119,8 @@ public boolean equals(Object obj) { return false; if (!Utils.nullableEqual(vol_notification, ((VolumeOperationData) obj).vol_notification)) return false; + if (!Utils.nullableEqual(vol_bt, ((VolumeOperationData) obj).vol_bt)) + return false; return true; } @@ -122,7 +129,8 @@ public boolean isValid() { return isNotNegative(vol_ring) || isNotNegative(vol_media) || isNotNegative(vol_alarm) - || isNotNegative(vol_notification); + || isNotNegative(vol_notification) + || isNotNegative(vol_bt); } @Override @@ -136,6 +144,7 @@ public void writeToParcel(Parcel parcel, int i) { parcel.writeValue(vol_media); parcel.writeValue(vol_alarm); parcel.writeValue(vol_notification); + parcel.writeValue(vol_bt); } public static final Creator CREATOR @@ -154,6 +163,7 @@ private VolumeOperationData(Parcel in) { vol_media = (Integer) in.readValue(Integer.class.getClassLoader()); vol_alarm = (Integer) in.readValue(Integer.class.getClassLoader()); vol_notification = (Integer) in.readValue(Integer.class.getClassLoader()); + vol_bt = (Integer) in.readValue(Integer.class.getClassLoader()); } private static boolean isNotNegative(@Nullable Integer value) { diff --git a/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationDataFactory.java b/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationDataFactory.java index 52a68975..53ff604e 100644 --- a/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationDataFactory.java +++ b/app/src/main/java/ryey/easer/plugins/operation/volume/VolumeOperationDataFactory.java @@ -37,7 +37,7 @@ public Class dataClass() { @NonNull @Override public VolumeOperationData dummyData() { - return new VolumeOperationData(1, 2, null, 0); + return new VolumeOperationData(1, 2, null, 0, null); } @ValidData diff --git a/app/src/main/res/layout/plugin_operation__launch_app.xml b/app/src/main/res/layout/plugin_operation__launch_app.xml new file mode 100644 index 00000000..b9866246 --- /dev/null +++ b/app/src/main/res/layout/plugin_operation__launch_app.xml @@ -0,0 +1,37 @@ + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/plugin_operation__volume.xml b/app/src/main/res/layout/plugin_operation__volume.xml index fbc1da54..7279fdb6 100644 --- a/app/src/main/res/layout/plugin_operation__volume.xml +++ b/app/src/main/res/layout/plugin_operation__volume.xml @@ -3,7 +3,8 @@ xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" - android:layout_height="match_parent"> + android:layout_height="match_parent" + tools:layout_editor_absoluteY="81dp"> + app:layout_constraintTop_toTopOf="parent" /> + app:layout_constraintTop_toBottomOf="@id/seekBar_ring" /> + app:layout_constraintTop_toBottomOf="@id/seekBar_media" /> + app:layout_constraintTop_toBottomOf="@id/seekBar_alarm" /> + + + + \ No newline at end of file diff --git a/app/src/main/res/values-zh/plugins.xml b/app/src/main/res/values-zh/plugins.xml index b9a1db7a..473f8836 100644 --- a/app/src/main/res/values-zh/plugins.xml +++ b/app/src/main/res/values-zh/plugins.xml @@ -155,5 +155,10 @@ 媒體/音樂 鬧鈴 通知 + 藍牙 + + 啓動程序 + 程序 + 包名 diff --git a/app/src/main/res/values/plugins.xml b/app/src/main/res/values/plugins.xml index 0d187865..9a3e1df6 100644 --- a/app/src/main/res/values/plugins.xml +++ b/app/src/main/res/values/plugins.xml @@ -163,5 +163,10 @@ Media Alarm Notification + Bluetooth + + Launch App + App + Package Name \ No newline at end of file diff --git a/utils/new_operation.py b/utils/new_operation.py index 5512d3aa..3f8984b0 100755 --- a/utils/new_operation.py +++ b/utils/new_operation.py @@ -16,12 +16,17 @@ import os.path import templates -template_map = { - 'plugin': templates.tmpl_operation_plugin, - 'data': templates.tmpl_operation_data, - 'data_factory': templates.tmpl_operation_data_factory, - 'view_fragment': templates.tmpl_plugin_view_fragment, - 'loader': templates.tmpl_operation_loader, +template_maps = { + 'main': { + 'plugin': templates.tmpl_operation_plugin, + 'data': templates.tmpl_operation_data, + 'data_factory': templates.tmpl_operation_data_factory, + 'view_fragment': templates.tmpl_plugin_view_fragment, + 'loader': templates.tmpl_operation_loader, + }, + 'androidTest': { + 'androidTest$data': templates.tmpl_operation_androidTest_data, + }, } def new_operation(cname, identifier): @@ -33,16 +38,18 @@ def new_operation(cname, identifier): pdef['data_factory'] = "{}OperationDataFactory".format(cname) pdef['view_fragment'] = "{}PluginViewFragment".format(cname) pdef['loader'] = "{}Loader".format(cname) - dest = '../app/src/main/java/ryey/easer/plugins/operation' - dest = "{}/{}".format(dest, identifier) - if not os.path.isfile(dest): - os.mkdir(dest) - for k in template_map: - class_content = template_map[k].format_map(pdef) - with open("{}/{}.java".format(dest, pdef[k]), 'w') as fd: - fd.write(templates.tmpl_copyright) - fd.write('\n') - fd.write(class_content) + pdef['androidTest$data'] = "{}OperationDataTest".format(cname) + for t, template_map in template_maps.items(): + dest = "app/src/{}/java/ryey/easer/plugins/operation/{}".format(t, identifier) + dest = "utils/{}/{}".format(t, identifier) + if not os.path.isfile(dest): + os.mkdir(dest) + for k in template_map: + class_content = template_map[k].format_map(pdef) + with open("{}/{}.java".format(dest, pdef[k]), 'w') as fd: + fd.write(templates.tmpl_copyright) + fd.write('\n') + fd.write(class_content) if __name__ == '__main__': parser = argparse.ArgumentParser() diff --git a/utils/templates.py b/utils/templates.py index 6835bb1d..e69bbb64 100644 --- a/utils/templates.py +++ b/utils/templates.py @@ -254,3 +254,26 @@ class {data_factory} implements OperationDataFactory<{data}> {{ }} ''' +tmpl_operation_androidTest_data = '''package {package}; + +import android.os.Parcel; + +import org.junit.Test; + +import ryey.easer.plugins.TestHelper; + +import static org.junit.Assert.assertEquals; + +public class {androidTest$data} {{ + + @Test + public void testParcel() {{ + {data} dummyData = new {data_factory}().dummyData(); + Parcel parcel = TestHelper.writeToParcel(dummyData); + {data} parceledData = {data}.CREATOR.createFromParcel(parcel); + assertEquals(dummyData, parceledData); + }} + +}} +''' +