diff --git a/.idea/misc.xml b/.idea/misc.xml index 56b4126c..157352a8 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -2,9 +2,10 @@ - + - + + diff --git a/app/build.gradle b/app/build.gradle index c776f33b..5823e9c4 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -37,15 +37,14 @@ repositories { dependencies { compile fileTree(include: ['*.jar'], dir: 'libs') + testCompile 'junit:junit:4.12' compile 'com.android.support:appcompat-v7:25.0.0' compile 'com.android.support:design:25.0.0' - testCompile 'junit:junit:4.12' + compile 'com.afollestad.material-dialogs:core:0.9.2.3' compile 'com.google.code.gson:gson:2.8.0' - compile 'com.sothree.slidinguppanel:library:3.3.1' compile('de.psdev.licensesdialog:licensesdialog:1.8.1') - compile 'com.squareup.duktape:duktape-android:1.1.0' compile 'com.furture.react:DuktapeJava:1.1.0' compile 'com.zzhoujay.markdown:markdown:1.0.2' @@ -54,15 +53,9 @@ dependencies { compile 'com.afollestad.material-dialogs:commons:0.9.2.3' compile 'com.makeramen:roundedimageview:2.2.1' compile 'com.rengwuxian.materialedittext:library:2.0.3' - compile(name:'920-common-release', ext:'aar'){ - transitive = true - } - compile(name:'920-styles-debug', ext:'aar'){ - transitive = true - } - compile(name:'920-file_explorer-release', ext:'aar'){ - transitive = true - } + compile(name:'920-common-release', ext:'aar') + compile(name:'920-styles-debug', ext:'aar') + compile(name:'920-file_explorer-release', ext:'aar') compile(name:'920-app-debug', ext:'aar') diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index d5e86975..85fc7dc2 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -72,9 +72,90 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/assets/sample_hello_big_sister.js b/app/src/main/assets/sample_hello_big_sister.js new file mode 100644 index 00000000..c478c6ac --- /dev/null +++ b/app/src/main/assets/sample_hello_big_sister.js @@ -0,0 +1,4 @@ +toast("大姐姐好") +for(var i = 0; i < 10; i++){ + toast("大姐姐今年有" + i + "块钱~"); +} \ No newline at end of file diff --git a/app/src/main/assets/sample_open_wechat_moment.js b/app/src/main/assets/sample_open_wechat_moment.js index 82fa1cca..03a71740 100644 --- a/app/src/main/assets/sample_open_wechat_moment.js +++ b/app/src/main/assets/sample_open_wechat_moment.js @@ -1,5 +1,3 @@ launchApp("微信"); -sleep(500); -click("发现"); -sleep(500); -click("朋友圈"); \ No newline at end of file +while(!click("发现")); +while(!click("朋友圈")); \ No newline at end of file diff --git a/app/src/main/java/com/stardust/EditAndRunIntentActivity.java b/app/src/main/java/com/stardust/EditAndRunIntentActivity.java new file mode 100644 index 00000000..2f05de55 --- /dev/null +++ b/app/src/main/java/com/stardust/EditAndRunIntentActivity.java @@ -0,0 +1,29 @@ +package com.stardust; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.stardust.scriptdroid.BaseActivity; +import com.stardust.scriptdroid.EditActivity; + +/** + * Created by Stardust on 2017/2/2. + */ + +public class EditAndRunIntentActivity extends BaseActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + handleIntent(); + } + + private void handleIntent() { + Intent intent = getIntent(); + String path = intent.getData().getPath(); + if (!TextUtils.isEmpty(path)) + EditActivity.editFile(this, path); + } +} diff --git a/app/src/main/java/com/stardust/UIActionPerformActivity.java b/app/src/main/java/com/stardust/UIActionPerformActivity.java index 2ed00641..25865fda 100644 --- a/app/src/main/java/com/stardust/UIActionPerformActivity.java +++ b/app/src/main/java/com/stardust/UIActionPerformActivity.java @@ -1,5 +1,6 @@ package com.stardust; +import android.app.Activity; import android.content.Intent; import android.os.Bundle; import android.support.v7.app.AppCompatActivity; @@ -15,9 +16,9 @@ import com.stardust.scriptdroid.droid.runtime.DroidRuntime; public class UIActionPerformActivity extends AppCompatActivity { - private static volatile Runnable action; + private static volatile UIAction action; - public static void performAction(Runnable action) { + public static void performAction(UIAction action) { if (UIActionPerformActivity.action != null) { return; } @@ -30,10 +31,20 @@ public class UIActionPerformActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); DroidRuntime.setContext(this); - action.run(); + action.setActivity(this).run(); } + public abstract static class UIAction implements Runnable { + + protected Activity mActivity; + + public UIAction setActivity(Activity activity) { + mActivity = activity; + return this; + } + + } } diff --git a/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java b/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java new file mode 100644 index 00000000..58fcc3cb --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/AboutActivity.java @@ -0,0 +1,89 @@ +package com.stardust.scriptdroid; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.os.Bundle; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.View; +import android.widget.Toast; + +import com.stardust.scriptdroid.tool.IntentTool; +import com.stardust.view.ViewBinder; +import com.stardust.view.ViewBinding; + +/** + * Created by Stardust on 2017/2/2. + */ + +public class AboutActivity extends BaseActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setUpUI(); + } + + private void setUpUI() { + setContentView(R.layout.activity_about); + setUpToolbar(); + ViewBinder.bind(this); + } + + private void setUpToolbar() { + Toolbar toolbar = $(R.id.toolbar); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + + @ViewBinding.Click(R.id.github) + private void openGitHub() { + IntentTool.goToLink(this, getString(R.string.my_github)); + } + + @ViewBinding.Click(R.id.qq) + private void openQQToChatWithMe() { + String qq = getString(R.string.qq); + IntentTool.goToQQ(this, qq); + } + + @ViewBinding.Click(R.id.email) + private void openEmailToSendMe() { + String email = getString(R.string.email); + IntentTool.goToMail(this, email); + } + + + @ViewBinding.Click(R.id.donate) + private void showDonateMeDialog() { + + } + + @ViewBinding.Click(R.id.share) + private void share() { + IntentTool.shareText(this, getString(R.string.share_app)); + } + + @ViewBinding.Click(R.id.icon) + private void lol() { + Toast.makeText(this, "略略略", Toast.LENGTH_LONG).show(); + } + + @ViewBinding.Click(R.id.developer) + private void hhh() { + Toast.makeText(this, "这是软件开发者(。・・)ノ", Toast.LENGTH_LONG).show(); + } + + private void setClipText(CharSequence label, CharSequence text) { + ClipboardManager clipboardManager = (ClipboardManager) getSystemService(CLIPBOARD_SERVICE); + clipboardManager.setPrimaryClip(ClipData.newPlainText(label, text)); + Toast.makeText(this, label + getString(R.string.text_already_copy_to_clip), Toast.LENGTH_SHORT).show(); + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/App.java b/app/src/main/java/com/stardust/scriptdroid/App.java index 1d542898..8d2e3d0f 100644 --- a/app/src/main/java/com/stardust/scriptdroid/App.java +++ b/app/src/main/java/com/stardust/scriptdroid/App.java @@ -2,6 +2,8 @@ package com.stardust.scriptdroid; import android.app.Application; +import com.stardust.util.CrashHandler; + /** * Created by Stardust on 2017/1/27. */ @@ -16,6 +18,7 @@ public class App extends Application { public void onCreate() { super.onCreate(); + Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class)); instance = this; } } diff --git a/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java b/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java new file mode 100644 index 00000000..9e5f4c66 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/AssistModeSwitchService.java @@ -0,0 +1,53 @@ +package com.stardust.scriptdroid; + +import android.app.PendingIntent; +import android.app.Service; +import android.content.Intent; +import android.os.IBinder; +import android.support.annotation.Nullable; + +import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService; +import com.stardust.scriptdroid.ui.AssistModeSwitchNotification; + +/** + * Created by Stardust on 2017/2/2. + */ +public class AssistModeSwitchService extends Service { + + public static PendingIntent getStartIntent() { + Intent intent = new Intent(App.getApp(), AssistModeSwitchService.class) + .putExtra("intentValid", true) + .putExtra("switch", "assistMode"); + return PendingIntent.getService(App.getApp(), 0, intent, 0); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + boolean intentValid = intent.getBooleanExtra("intentValid", false); + if (intentValid) { + String action = intent.getStringExtra("action"); + if (action != null) { + if (action.equals("assistMode")) { + ActionPerformService.setAssistModeEnable(!ActionPerformService.isAssistModeEnable()); + } else { + AssistModeSwitchNotification.setEnable(false); + } + } + } + stopSelf(); + return super.onStartCommand(intent, flags, startId); + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + public static PendingIntent getDeletePendingIntent() { + Intent deleteIntent = new Intent(App.getApp(), AssistModeSwitchService.class) + .putExtra("intentValid", true) + .putExtra("switch", "assistModeNotification"); + return PendingIntent.getService(App.getApp(), 0, deleteIntent, 0); + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/BaseActivity.java b/app/src/main/java/com/stardust/scriptdroid/BaseActivity.java index 5786651e..c29b14e5 100644 --- a/app/src/main/java/com/stardust/scriptdroid/BaseActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/BaseActivity.java @@ -6,10 +6,11 @@ import android.support.v7.app.AppCompatActivity; import android.view.View; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; -import java.util.stream.Stream; import static android.content.pm.PackageManager.PERMISSION_DENIED; +import static android.content.pm.PackageManager.PERMISSION_GRANTED; /** * Created by Stardust on 2017/1/23. @@ -30,6 +31,10 @@ public class BaseActivity extends AppCompatActivity { String[] requestPermissions = getRequestPermissions(permissions); if (requestPermissions.length > 0) requestPermissions(requestPermissions, PERMISSION_REQUEST_CODE); + } else { + int[] grantResults = new int[permissions.length]; + Arrays.fill(grantResults, PERMISSION_GRANTED); + onRequestPermissionsResult(PERMISSION_REQUEST_CODE, permissions, grantResults); } } diff --git a/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java b/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java new file mode 100644 index 00000000..f4c1ff98 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ErrorReportActivity.java @@ -0,0 +1,100 @@ +package com.stardust.scriptdroid; + +import android.content.ClipData; +import android.content.ClipboardManager; +import android.os.Build; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.v7.widget.Toolbar; +import android.widget.Toast; + +import com.afollestad.materialdialogs.DialogAction; +import com.afollestad.materialdialogs.MaterialDialog; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * Created by Stardust on 2017/2/2. + */ + +public class ErrorReportActivity extends BaseActivity { + + protected void onCreate(Bundle savedInstanceState) { + try { + super.onCreate(savedInstanceState); + setUpUI(); + handleIntent(); + + } catch (Throwable throwable) { + throwable.printStackTrace(); + } + } + + private void handleIntent() { + String message = getIntent().getStringExtra("message"); + final String errorDetail = getIntent().getStringExtra("error"); + new MaterialDialog.Builder(this) + .content(message) + .positiveText("退出") + .negativeText("复制调试信息") + .onPositive(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { + exit(); + } + }) + .onNegative(new MaterialDialog.SingleButtonCallback() { + @Override + public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) { + copyToClip(getDeviceMessage() + errorDetail); + exitAfter(1000); + } + }) + .cancelable(false) + .show(); + } + + private String getDeviceMessage() { + return "Android: " + Build.VERSION.SDK_INT + "\n"; + } + + private void exitAfter(long millis) { + new Timer().schedule(new TimerTask() { + @Override + public void run() { + exit(); + } + }, millis); + } + + private void copyToClip(String text) { + ((ClipboardManager) getSystemService(CLIPBOARD_SERVICE)) + .setPrimaryClip(ClipData.newPlainText("Debug", text)); + Toast.makeText(ErrorReportActivity.this, R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show(); + } + + private void setUpUI() { + setContentView(R.layout.activity_error_report); + setUpToolbar(); + } + + private void setUpToolbar() { + Toolbar toolbar = $(R.id.toolbar); + toolbar.setTitle(getString(R.string.text_error_report)); + setSupportActionBar(toolbar); + getSupportActionBar().setHomeButtonEnabled(false); + } + + private void exit() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { + finishAffinity(); + } else { + finish(); + } + + } + +} + + diff --git a/app/src/main/java/com/stardust/scriptdroid/ImportIntentActivity.java b/app/src/main/java/com/stardust/scriptdroid/ImportIntentActivity.java new file mode 100644 index 00000000..4c89d1f0 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ImportIntentActivity.java @@ -0,0 +1,48 @@ +package com.stardust.scriptdroid; + +import android.content.Intent; +import android.os.Bundle; +import android.support.annotation.NonNull; +import android.support.annotation.Nullable; +import android.text.TextUtils; + +import com.afollestad.materialdialogs.MaterialDialog; +import com.stardust.scriptdroid.droid.script.file.ScriptFile; +import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList; + +import java.io.File; + +/** + * Created by Stardust on 2017/2/2. + */ + +public class ImportIntentActivity extends BaseActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + handleIntent(); + } + + private void handleIntent() { + Intent intent = getIntent(); + final String path = intent.getData().getPath(); + if (!TextUtils.isEmpty(path)) { + new MaterialDialog.Builder(this) + .title(R.string.text_please_input_name) + .input(getString(R.string.text_name), new File(path).getName(), new MaterialDialog.InputCallback() { + @Override + public void onInput(@NonNull MaterialDialog dialog, CharSequence input) { + SharedPrefScriptFileList.getInstance().add(new ScriptFile(input.toString(), path)); + startMainActivity(); + } + }) + .show(); + } + } + + private void startMainActivity() { + startActivity(new Intent(this, MainActivity.class) + .addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)); + } +} \ No newline at end of file diff --git a/app/src/main/java/com/stardust/scriptdroid/MainActivity.java b/app/src/main/java/com/stardust/scriptdroid/MainActivity.java index 0ddaabc4..b1bca0cb 100644 --- a/app/src/main/java/com/stardust/scriptdroid/MainActivity.java +++ b/app/src/main/java/com/stardust/scriptdroid/MainActivity.java @@ -1,7 +1,6 @@ package com.stardust.scriptdroid; import android.Manifest; -import android.content.ActivityNotFoundException; import android.content.Intent; import android.content.pm.PackageManager; import android.os.Bundle; @@ -12,17 +11,17 @@ import android.support.v7.app.ActionBarDrawerToggle; import android.support.v7.widget.Toolbar; import android.text.InputType; import android.view.View; -import android.widget.Toast; import com.afollestad.materialdialogs.DialogAction; import com.afollestad.materialdialogs.MaterialDialog; +import com.afollestad.materialdialogs.folderselector.FileChooserDialog; import com.stardust.app.NotRemindAgainDialog; import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService; import com.stardust.scriptdroid.droid.script.file.ScriptFile; import com.stardust.scriptdroid.droid.script.file.ScriptFileList; import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList; -import com.stardust.scriptdroid.file.FileChooser; import com.stardust.scriptdroid.file.FileUtils; +import com.stardust.scriptdroid.tool.BackPressedHandler; import com.stardust.scriptdroid.ui.ScriptFileOperation; import com.stardust.scriptdroid.ui.ScriptListRecyclerView; import com.stardust.scriptdroid.ui.SlideMenuFragment; @@ -32,22 +31,19 @@ import com.stardust.view.ViewBinding; import com.stardust.view.accessibility.AccessibilityServiceUtils; import java.io.File; -import java.io.InputStream; -public class MainActivity extends BaseActivity { +public class MainActivity extends BaseActivity implements FileChooserDialog.FileCallback { private SlidingUpPanel mAddFilePanel; private ScriptListRecyclerView mScriptListRecyclerView; private ScriptFileList mScriptFileList; - private FileChooser mFileChooser; private DrawerLayout mDrawerLayout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setUpUI(); - setUpFileChooser(); checkPermissions(); } @@ -72,19 +68,6 @@ public class MainActivity extends BaseActivity { } } - private void setUpFileChooser() { - mFileChooser = new FileChooser(this); - mFileChooser.setOnFileChoseListener(new FileChooser.OnFileChoseListener() { - @Override - public void onFileChose(InputStream inputStream) { - String path = FileUtils.getPath(inputStream); - if (path != null) { - MainActivity.this.addScriptFile(path); - } - } - }); - } - private void addScriptFile(final String path) { new MaterialDialog.Builder(this).title(R.string.text_name) .inputType(InputType.TYPE_CLASS_TEXT) @@ -159,19 +142,14 @@ public class MainActivity extends BaseActivity { @ViewBinding.Click(R.id.import_from_file) private void showFileChooser() { - mFileChooser.startFileManagerToChoose("*/*", new FileChooser.FileManagerNotFoundHandler() { - @Override - public void handle(ActivityNotFoundException exception, String mimeType) { - exception.printStackTrace(); - Snackbar.make(mDrawerLayout, R.string.text_file_manager_not_found, Snackbar.LENGTH_SHORT).show(); - } - }); + new FileChooserDialog.Builder(this) + .extensionsFilter(".js", ".txt") + .show(); } @ViewBinding.Click(R.id.setting) private void startSettingActivity() { - //TODO create Setting Activity - Toast.makeText(this, "暂无", Toast.LENGTH_LONG).show(); + startActivity(new Intent(this, SettingsActivity.class)); } @ViewBinding.Click(R.id.exit) @@ -179,10 +157,6 @@ public class MainActivity extends BaseActivity { super.finish(); } - public void onActivityResult(int requestCode, int resultCode, Intent data) { - mFileChooser.onActivityResult(requestCode, resultCode, data); - } - @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { @@ -191,4 +165,16 @@ public class MainActivity extends BaseActivity { mScriptListRecyclerView.getAdapter().notifyDataSetChanged(); } } + + @Override + public void onFileSelection(@NonNull FileChooserDialog dialog, @NonNull File file) { + addScriptFile(file.getPath()); + } + + + private BackPressedHandler mBackPressedHandler = new BackPressedHandler.DoublePressExit(this); + @Override + public void onBackPressed() { + mBackPressedHandler.onBackPressed(); + } } \ No newline at end of file diff --git a/app/src/main/java/com/stardust/scriptdroid/NonUiInitializer.java b/app/src/main/java/com/stardust/scriptdroid/NonUiInitializer.java index 8d50ced1..503b6d22 100644 --- a/app/src/main/java/com/stardust/scriptdroid/NonUiInitializer.java +++ b/app/src/main/java/com/stardust/scriptdroid/NonUiInitializer.java @@ -18,7 +18,7 @@ public class NonUiInitializer { private static final Map SAMPLES = new MapEntries() .entry("sample_open_wechat_moment.js", R.string.text_sample_open_what_moment) .entry("sample_open_running_services.js", R.string.text_sample_open_running_services) - .entry("sample_simple_calculator.js", R.string.text_sample_simple_calculator) + .entry("sample_hello_big_sister.js", R.string.text_sample_hello_big_sister) .map(); private static NonUiInitializer instance = new NonUiInitializer(); @@ -35,7 +35,7 @@ public class NonUiInitializer { } - public void copySampleScriptFileIfNeeded(){ + public void copySampleScriptFileIfNeeded() { if (!Pref.def().getBoolean(Pref.SAMPLE_SCRIPTS_COPIED, false)) { copySampleScriptFile(); } diff --git a/app/src/main/java/com/stardust/scriptdroid/SettingsActivity.java b/app/src/main/java/com/stardust/scriptdroid/SettingsActivity.java new file mode 100644 index 00000000..66c27ff7 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/SettingsActivity.java @@ -0,0 +1,99 @@ +package com.stardust.scriptdroid; + +import android.content.Intent; +import android.os.Bundle; +import android.preference.Preference; +import android.preference.PreferenceScreen; +import android.support.annotation.Nullable; +import android.support.v7.widget.Toolbar; +import android.view.View; + +import com.stardust.util.MapEntries; + +import java.util.Map; + +import de.psdev.licensesdialog.LicensesDialog; + +/** + * Created by Stardust on 2017/2/2. + */ + +public class SettingsActivity extends BaseActivity { + + @Override + protected void onCreate(@Nullable Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setUpUI(); + } + + private void setUpUI() { + setContentView(R.layout.activity_settings); + setUpToolbar(); + getFragmentManager().beginTransaction().replace(R.id.fragment_setting, new PreferenceFragment()).commit(); + } + + private void setUpToolbar() { + Toolbar toolbar = $(R.id.toolbar); + toolbar.setTitle(R.string.text_setting); + setSupportActionBar(toolbar); + getSupportActionBar().setDisplayHomeAsUpEnabled(true); + toolbar.setNavigationOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + finish(); + } + }); + } + + + public static class PreferenceFragment extends android.preference.PreferenceFragment { + + private Map ACTION_MAP; + + + @Override + public void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + addPreferencesFromResource(R.xml.preferences); + } + + @Override + public void onStart() { + super.onStart(); + ACTION_MAP = new MapEntries() + .entry(getString(R.string.text_about), new Runnable() { + @Override + public void run() { + startActivity(new Intent(getActivity(), AboutActivity.class)); + } + }) + .entry(getString(R.string.text_licenses), new Runnable() { + @Override + public void run() { + showLicenseDialog(); + } + }) + .map(); + } + + @Override + public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { + Runnable action = ACTION_MAP.get(preference.getTitle().toString()); + if (action != null) { + action.run(); + return true; + } else { + return super.onPreferenceTreeClick(preferenceScreen, preference); + } + } + + private void showLicenseDialog() { + new LicensesDialog.Builder(getActivity()) + .setNotices(R.raw.licenses) + .setIncludeOwnLicense(true) + .build() + .showAppCompat(); + } + + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java b/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java index e069fd90..52f336f7 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/Droid.java @@ -1,7 +1,7 @@ package com.stardust.scriptdroid.droid; import com.stardust.scriptdroid.droid.runtime.DroidRuntime; -import com.stardust.scriptdroid.droid.script.GBJDuktapeJavaScriptEngine; +import com.stardust.scriptdroid.droid.script.DuktapeJavaScriptEngine; import com.stardust.scriptdroid.droid.script.JavaScriptEngine; import com.stardust.scriptdroid.file.FileUtils; @@ -19,7 +19,7 @@ public class Droid { } private static final DroidRuntime RUNTIME = DroidRuntime.getRuntime(); - private static final JavaScriptEngine JAVA_SCRIPT_ENGINE = new GBJDuktapeJavaScriptEngine(RUNTIME); + private static final JavaScriptEngine JAVA_SCRIPT_ENGINE = new DuktapeJavaScriptEngine(RUNTIME); private static final OnRunFinishedListener DEFAULT_LISTENER = new OnRunFinishedListener() { @Override public void onRunFinished(Object result, Exception e) { diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java index 3f1b4af7..33f1175b 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/DroidRuntime.java @@ -10,7 +10,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Toast; import com.afollestad.materialdialogs.MaterialDialog; -import com.stardust.UIActionPerformActivity; import com.stardust.scriptdroid.App; import com.stardust.scriptdroid.R; import com.stardust.scriptdroid.droid.runtime.action.Action; @@ -194,12 +193,7 @@ public class DroidRuntime implements IDroidRuntime { } public MaterialDialog show(final MaterialDialog.Builder dialog) { - UIActionPerformActivity.performAction(new Runnable() { - @Override - public void run() { - dialog.show(); - } - }); + return null; } } diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformService.java b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformService.java index c9bd77b5..c07a9f23 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformService.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/runtime/action/ActionPerformService.java @@ -3,6 +3,7 @@ package com.stardust.scriptdroid.droid.runtime.action; import android.accessibilityservice.AccessibilityService; import android.content.ClipData; import android.content.ClipboardManager; +import android.content.Intent; import android.graphics.Rect; import android.os.Build; import android.preference.PreferenceManager; @@ -27,6 +28,10 @@ import java.util.List; public class ActionPerformService extends AccessibilityService { + + public static final String ACTION_CHANGE_ASSIST_MODE = App.getApp().getPackageName() + ".ACTION_CHANGE_ASSIST_MODE"; + + private static final String TAG = "ActionPerformService"; private static final String KEY_ASSIST_MODE_ENABLE = "ASSIST_MODE_ENABLE"; private static ActionPerformService instance; @@ -65,6 +70,7 @@ public class ActionPerformService extends AccessibilityService { public static void setAssistModeEnable(boolean assistModeEnable) { ActionPerformService.assistModeEnable = assistModeEnable; PreferenceManager.getDefaultSharedPreferences(App.getApp()).edit().putBoolean(KEY_ASSIST_MODE_ENABLE, assistModeEnable).apply(); + App.getApp().sendBroadcast(new Intent(ACTION_CHANGE_ASSIST_MODE).putExtra("enable", assistModeEnable)); } @Override diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java b/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java index 13500f53..abf4f662 100644 --- a/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java +++ b/app/src/main/java/com/stardust/scriptdroid/droid/script/DuktapeJavaScriptEngine.java @@ -1,12 +1,19 @@ package com.stardust.scriptdroid.droid.script; -import android.util.Log; +import android.util.Pair; -import com.squareup.duktape.Duktape; +import com.efurture.script.JSTransformer; +import com.furture.react.DuktapeEngine; +import com.stardust.scriptdroid.App; import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime; -import static com.stardust.scriptdroid.droid.script.JavaScriptEngine.Init.readInitScript; - +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; /** * Created by Stardust on 2017/1/27. @@ -14,54 +21,100 @@ import static com.stardust.scriptdroid.droid.script.JavaScriptEngine.Init.readIn public class DuktapeJavaScriptEngine implements JavaScriptEngine { - private static final String TAG = "DuktapeJavaScriptEngine"; - private Duktape mDuktape = Duktape.create(); - private boolean mRecycled = false; + private final List> mDuktapeEngineList = new ArrayList<>(); + private static final String INIT_SCRIPT; + private Map mVariableMap = new HashMap<>(); + + static { + try { + INIT_SCRIPT = JSTransformer.parse(new StringReader(Init.INIT_SCRIPT)); + } catch (IOException e) { + e.printStackTrace(); + throw new RuntimeException(e); + } + } public DuktapeJavaScriptEngine(IDroidRuntime runtime) { setRuntime(runtime); - execute(readInitScript()); + } - public void setRuntime(IDroidRuntime runtime) { + private void setRuntime(IDroidRuntime runtime) { set("droid", IDroidRuntime.class, runtime); } - @Override - public Object execute(String script) { - return mDuktape.evaluate(script); + public Object execute(String script) throws IOException { + DuktapeEngine duktapeEngine = new DuktapeEngine(); + init(duktapeEngine); + add(duktapeEngine, Thread.currentThread()); + Object result; + try { + result = duktapeEngine.execute(JSTransformer.parse(new StringReader(script))); + } catch (IOException e) { + remove(duktapeEngine); + throw e; + } + remove(duktapeEngine); + return result; } + private void init(DuktapeEngine duktapeEngine) { + duktapeEngine.put("context", App.getApp()); + duktapeEngine.execute(INIT_SCRIPT); + for (Map.Entry variable : mVariableMap.entrySet()) { + duktapeEngine.put(variable.getKey(), variable.getValue()); + } + + } + + private void remove(DuktapeEngine duktapeEngine) { + duktapeEngine.destory(); + synchronized (mDuktapeEngineList) { + Iterator> iterator = mDuktapeEngineList.iterator(); + while (iterator.hasNext()) { + Pair pair = iterator.next(); + if (pair.first == duktapeEngine) { + stop(pair.first, pair.second); + } + iterator.remove(); + break; + } + } + } + + private void stop(DuktapeEngine engine, Thread thread) { + try { + thread.interrupt(); + } catch (Exception e) { + e.printStackTrace(); + } + engine.destory(); + } + + private void add(DuktapeEngine duktapeEngine, Thread thread) { + synchronized (mDuktapeEngineList) { + mDuktapeEngineList.add(0, new Pair<>(duktapeEngine, thread)); + } + } + + @Override public void set(String varName, Class c, T value) { - mDuktape.set(varName, c, value); + mVariableMap.put(varName, value); } @Override public int stopAll() { - mDuktape.close(); - return 1; - } - - public void recycle() { - if (!mRecycled) { - mDuktape.close(); - mRecycled = true; - } - } - - @Override - public void finalize() throws Throwable { - try { - if (!mRecycled) { - Log.w(TAG, "Not recycled before finalize"); - recycle(); + int n; + synchronized (mDuktapeEngineList) { + for (Pair pair : mDuktapeEngineList) { + stop(pair.first, pair.second); } - } catch (Throwable throwable) { - throwable.printStackTrace(); + n = mDuktapeEngineList.size(); + mDuktapeEngineList.clear(); } - super.finalize(); + return n; } } diff --git a/app/src/main/java/com/stardust/scriptdroid/droid/script/GBJDuktapeJavaScriptEngine.java b/app/src/main/java/com/stardust/scriptdroid/droid/script/GBJDuktapeJavaScriptEngine.java deleted file mode 100644 index 5d01ada8..00000000 --- a/app/src/main/java/com/stardust/scriptdroid/droid/script/GBJDuktapeJavaScriptEngine.java +++ /dev/null @@ -1,120 +0,0 @@ -package com.stardust.scriptdroid.droid.script; - -import android.util.Pair; - -import com.efurture.script.JSTransformer; -import com.furture.react.DuktapeEngine; -import com.stardust.scriptdroid.App; -import com.stardust.scriptdroid.droid.runtime.api.IDroidRuntime; - -import java.io.IOException; -import java.io.StringReader; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.Iterator; -import java.util.List; -import java.util.Map; - -/** - * Created by Stardust on 2017/1/27. - */ - -public class GBJDuktapeJavaScriptEngine implements JavaScriptEngine { - - - private final List> mDuktapeEngineList = new ArrayList<>(); - private static final String INIT_SCRIPT; - private Map mVariableMap = new HashMap<>(); - - static { - try { - INIT_SCRIPT = JSTransformer.parse(new StringReader(Init.INIT_SCRIPT)); - } catch (IOException e) { - e.printStackTrace(); - throw new RuntimeException(e); - } - } - - public GBJDuktapeJavaScriptEngine(IDroidRuntime runtime) { - setRuntime(runtime); - - } - - private void setRuntime(IDroidRuntime runtime) { - set("droid", IDroidRuntime.class, runtime); - } - - @Override - public Object execute(String script) throws IOException { - DuktapeEngine duktapeEngine = new DuktapeEngine(); - init(duktapeEngine); - add(duktapeEngine, Thread.currentThread()); - Object result; - try { - result = duktapeEngine.execute(JSTransformer.parse(new StringReader(script))); - } catch (IOException e) { - remove(duktapeEngine); - throw e; - } - remove(duktapeEngine); - return result; - } - - private void init(DuktapeEngine duktapeEngine) { - duktapeEngine.put("context", App.getApp()); - duktapeEngine.execute(INIT_SCRIPT); - for (Map.Entry variable : mVariableMap.entrySet()) { - duktapeEngine.put(variable.getKey(), variable.getValue()); - } - - } - - private void remove(DuktapeEngine duktapeEngine) { - duktapeEngine.destory(); - synchronized (mDuktapeEngineList) { - Iterator> iterator = mDuktapeEngineList.iterator(); - while (iterator.hasNext()) { - Pair pair = iterator.next(); - if (pair.first == duktapeEngine) { - stop(pair.first, pair.second); - } - iterator.remove(); - break; - } - } - } - - private void stop(DuktapeEngine engine, Thread thread) { - try { - thread.interrupt(); - } catch (Exception e) { - e.printStackTrace(); - } - engine.destory(); - } - - private void add(DuktapeEngine duktapeEngine, Thread thread) { - synchronized (mDuktapeEngineList) { - mDuktapeEngineList.add(0, new Pair<>(duktapeEngine, thread)); - } - } - - @Override - public void set(String varName, Class c, T value) { - mVariableMap.put(varName, value); - } - - @Override - public int stopAll() { - int n; - synchronized (mDuktapeEngineList) { - for (Pair pair : mDuktapeEngineList) { - stop(pair.first, pair.second); - } - n = mDuktapeEngineList.size(); - mDuktapeEngineList.clear(); - } - return n; - } - -} diff --git a/app/src/main/java/com/stardust/scriptdroid/tool/BackPressedHandler.java b/app/src/main/java/com/stardust/scriptdroid/tool/BackPressedHandler.java new file mode 100644 index 00000000..e274a0df --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/tool/BackPressedHandler.java @@ -0,0 +1,40 @@ +package com.stardust.scriptdroid.tool; + +import android.app.Activity; +import android.widget.Toast; + +import com.stardust.scriptdroid.R; + +/** + * Created by Stardust on 2017/2/3. + */ +public interface BackPressedHandler { + + void onBackPressed(); + + class DoublePressExit implements BackPressedHandler { + + private final Activity mActivity; + private long mLastPressedMillis; + private long mDoublePressInterval = 1000; + + public DoublePressExit(Activity activity) { + mActivity = activity; + } + + public DoublePressExit setDoublePressInterval(long doublePressInterval) { + mDoublePressInterval = doublePressInterval; + return this; + } + + @Override + public void onBackPressed() { + if (System.currentTimeMillis() - mLastPressedMillis < mDoublePressInterval) { + mActivity.finish(); + } else { + mLastPressedMillis = System.currentTimeMillis(); + Toast.makeText(mActivity, R.string.text_press_again_to_exit, Toast.LENGTH_SHORT).show(); + } + } + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java b/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java new file mode 100644 index 00000000..ce3fe1a3 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/tool/IntentTool.java @@ -0,0 +1,48 @@ +package com.stardust.scriptdroid.tool; + +import android.content.Context; +import android.content.Intent; +import android.net.Uri; +import android.support.annotation.Nullable; + +/** + * Intent工具,用于Activity之间的跳转,调起其他应用程序等 + */ +public class IntentTool { + + public static void goToQQ(Context context, String qq) { + try { + String url = "mqqwpa://im/chat?chat_type=wpa&uin=" + qq; + context.startActivity(new Intent(Intent.ACTION_VIEW, Uri.parse(url))); + } catch (Exception exception) { + exception.printStackTrace(); + } + } + + public static void goToMail(Context context, String sendTo, @Nullable String title, @Nullable String content) { + Uri uri = Uri.parse("mailto:" + sendTo); + String[] email = {sendTo}; + Intent intent = new Intent(Intent.ACTION_SENDTO, uri); + intent.putExtra(Intent.EXTRA_CC, email); + if (title != null) + intent.putExtra(Intent.EXTRA_SUBJECT, title); + if (content != null) + intent.putExtra(Intent.EXTRA_TEXT, content); + context.startActivity(Intent.createChooser(intent, "请选择邮件应用")); + } + + public static void goToMail(Context context, String sendTo) { + goToMail(context, sendTo, null, null); + } + + public static void goToLink(Context context, String link) { + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(link)); + context.startActivity(intent); + } + + public static void shareText(Context context, String text) { + context.startActivity(new Intent(Intent.ACTION_SEND) + .putExtra(Intent.EXTRA_TEXT, text) + .setType("text/plain")); + } +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java b/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java new file mode 100644 index 00000000..22f39687 --- /dev/null +++ b/app/src/main/java/com/stardust/scriptdroid/ui/AssistModeSwitchNotification.java @@ -0,0 +1,83 @@ +package com.stardust.scriptdroid.ui; + +import android.app.Notification; +import android.app.NotificationManager; +import android.content.Context; +import android.preference.PreferenceManager; +import android.support.v4.app.NotificationCompat; + +import com.stardust.scriptdroid.App; +import com.stardust.scriptdroid.AssistModeSwitchService; +import com.stardust.scriptdroid.R; +import com.stardust.scriptdroid.droid.runtime.action.ActionPerformService; + +/** + * Created by Stardust on 2017/2/2. + */ + +public class AssistModeSwitchNotification { + + private static final int NOTIFY_ID = 11126; + private static final String KEY_ASSIST_MODE_NOTIFICATION = "KEY_ASSIST_MODE_NOTIFICATION"; + + private static boolean enable = false; + private static Notification notification; + + static { + readPreference(); + } + + public static boolean isEnable() { + return enable; + } + + public static void setEnable(boolean enable) { + if (AssistModeSwitchNotification.enable == enable) + return; + AssistModeSwitchNotification.enable = enable; + PreferenceManager.getDefaultSharedPreferences(App.getApp()).edit().putBoolean(KEY_ASSIST_MODE_NOTIFICATION, enable).apply(); + if (enable) { + showNotification(); + } else { + hideNotification(); + } + } + + public static void notifyAssistModeChanged() { + if (enable) { + setEnable(false); + setEnable(true); + } + } + + + private static void showNotification() { + notification = new NotificationCompat.Builder(App.getApp()) + .setAutoCancel(false) + .setSmallIcon(R.drawable.ic_robot_head) + .setDeleteIntent(AssistModeSwitchService.getDeletePendingIntent()) + .setContentText(ActionPerformService.isAssistModeEnable() ? + App.getApp().getString(R.string.text_assist_mode_enabled) : + App.getApp().getString(R.string.text_assist_mode_disabled)) + .setContentIntent(AssistModeSwitchService.getStartIntent()) + .build(); + showNotification(notification); + } + + private static void showNotification(Notification notification) { + NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.notify(NOTIFY_ID, notification); + } + + private static void hideNotification() { + NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE); + notificationManager.cancel(NOTIFY_ID); + } + + + private static void readPreference() { + enable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_ASSIST_MODE_NOTIFICATION, false); + setEnable(enable); + } + +} diff --git a/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java b/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java index 6043ef06..ab78b10e 100644 --- a/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java +++ b/app/src/main/java/com/stardust/scriptdroid/ui/SlideMenuFragment.java @@ -1,6 +1,9 @@ package com.stardust.scriptdroid.ui; +import android.content.BroadcastReceiver; +import android.content.Context; import android.content.Intent; +import android.content.IntentFilter; import android.os.Bundle; import android.support.annotation.Nullable; import android.support.design.widget.Snackbar; @@ -9,8 +12,6 @@ import android.support.v7.widget.SwitchCompat; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.CompoundButton; -import android.widget.Toast; import com.stardust.app.Fragment; import com.stardust.scriptdroid.DocumentActivity; @@ -21,7 +22,7 @@ import com.stardust.view.ViewBinder; import com.stardust.view.ViewBinding; import com.stardust.view.accessibility.AccessibilityServiceUtils; -import de.psdev.licensesdialog.LicensesDialog; +import static com.stardust.scriptdroid.droid.runtime.action.ActionPerformService.ACTION_CHANGE_ASSIST_MODE; /** * Created by Stardust on 2017/1/30. @@ -35,7 +36,8 @@ public class SlideMenuFragment extends Fragment { activity.getSupportFragmentManager().beginTransaction().replace(viewId, fragment).commit(); } - private SwitchCompat mAutoOperateServiceSwitch; + private SwitchCompat mAutoOperateServiceSwitch, mAssistServiceSwitch, mAssistServiceNotificationSwitch; + private Receiver mReceiver = new Receiver(); @Nullable @Override @@ -49,40 +51,68 @@ public class SlideMenuFragment extends Fragment { if (mAutoOperateServiceSwitch == null) { setUpSwitchCompat(); ViewBinder.bind(this); + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_CHANGE_ASSIST_MODE); + getContext().registerReceiver(mReceiver, filter); } - syncSwitchStatus(); + syncSwitchState(); } - private void syncSwitchStatus() { + private void syncSwitchState() { mAutoOperateServiceSwitch.postDelayed(new Runnable() { @Override public void run() { mAutoOperateServiceSwitch.setChecked(ActionPerformService.isEnable()); } }, 450); + mAssistServiceSwitch.setChecked(ActionPerformService.isAssistModeEnable()); + mAssistServiceNotificationSwitch.setChecked(AssistModeSwitchNotification.isEnable()); } private void setUpSwitchCompat() { mAutoOperateServiceSwitch = $(R.id.sw_auto_operate_service); - mAutoOperateServiceSwitch.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { - @Override - public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { - if (isChecked && !ActionPerformService.isEnable()) { - AccessibilityServiceUtils.goToPermissionSetting(getContext()); - } else if (!isChecked && ActionPerformService.isEnable()) { - ActionPerformService.disable(); - } - } - }); + mAssistServiceSwitch = $(R.id.sw_assist_service); + mAssistServiceNotificationSwitch = $(R.id.sw_assist_service_notification); } - @ViewBinding.Click(R.id.licenses) - private void showLicenseDialog() { - new LicensesDialog.Builder(getActivity()) - .setNotices(R.raw.licenses) - .setIncludeOwnLicense(true) - .build() - .showAppCompat(); + @ViewBinding.Click(R.id.syntax_and_api) + private void startSyntaxHelpActivity() { + startActivity(new Intent(getContext(), DocumentActivity.class)); + } + + @ViewBinding.Click(R.id.auto_operate_service) + private void clickAutoOperateServiceSwitch() { + mAutoOperateServiceSwitch.toggle(); + } + + @ViewBinding.Check(R.id.sw_auto_operate_service) + private void setAutoOperateServiceEnable(boolean enable) { + if (enable && !ActionPerformService.isEnable()) { + AccessibilityServiceUtils.goToPermissionSetting(getContext()); + } else if (!enable && ActionPerformService.isEnable()) { + ActionPerformService.disable(); + } + } + + @ViewBinding.Check(R.id.sw_assist_service) + private void setAssistServiceEnable(boolean enable) { + ActionPerformService.setAssistModeEnable(enable); + AssistModeSwitchNotification.notifyAssistModeChanged(); + } + + @ViewBinding.Click(R.id.assist_service) + private void toggleAssistServiceSwitch() { + mAssistServiceSwitch.toggle(); + } + + @ViewBinding.Check(R.id.sw_assist_service_notification) + private void setAssistServiceNotificationEnable(boolean enable) { + AssistModeSwitchNotification.setEnable(enable); + } + + @ViewBinding.Click(R.id.assist_service_notification) + private void toggleAssistServiceNotificationSwitch() { + mAssistServiceNotificationSwitch.toggle(); } @ViewBinding.Click(R.id.stop_all_running_scripts) @@ -94,19 +124,23 @@ public class SlideMenuFragment extends Fragment { Snackbar.make(getActivityContentView(), "没有正在运行的脚本", Snackbar.LENGTH_SHORT).show(); } - @ViewBinding.Click(R.id.syntax_and_api) - private void startSyntaxHelpActivity() { - startActivity(new Intent(getContext(), DocumentActivity.class)); + @Override + public void onDestroy() { + getContext().unregisterReceiver(mReceiver); + super.onDestroy(); } - @ViewBinding.Click(R.id.about_app) - private void startAboutActivity() { - // TODO: 2017/1/30 startAboutActivity - Toast.makeText(getContext(), "暂无", Toast.LENGTH_LONG).show(); + private class Receiver extends BroadcastReceiver { + + + @Override + public void onReceive(Context context, Intent intent) { + if (intent.getAction().equals(ACTION_CHANGE_ASSIST_MODE)) { + AssistModeSwitchNotification.notifyAssistModeChanged(); + mAssistServiceSwitch.setChecked(intent.getBooleanExtra("enable", false)); + } + } } - @ViewBinding.Click(R.id.auto_operate_service) - private void clickAutoOperateServiceSwitch() { - mAutoOperateServiceSwitch.setChecked(!mAutoOperateServiceSwitch.isChecked()); - } + } diff --git a/app/src/main/java/com/stardust/util/CrashHandler.java b/app/src/main/java/com/stardust/util/CrashHandler.java new file mode 100644 index 00000000..9006246d --- /dev/null +++ b/app/src/main/java/com/stardust/util/CrashHandler.java @@ -0,0 +1,47 @@ +package com.stardust.util; + +/** + * Created by Stardust on 2017/2/2. + */ + + +import android.content.Intent; +import android.util.Log; + +import com.stardust.scriptdroid.App; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.Thread.UncaughtExceptionHandler; + +public class CrashHandler implements UncaughtExceptionHandler { + private static final String TAG = "CrashHandler"; + private final Class mErrorReportClass; + + public CrashHandler(Class errorReportClass) { + this.mErrorReportClass = errorReportClass; + } + + public void uncaughtException(Thread thread, Throwable ex) { + try { + Log.e("CrashHandler", "Uncaught Exception!!!"); + ex.printStackTrace(); + String t = "很抱歉,程序遇到未知错误,即将停止运行\n错误代码:" + ex.toString(); + Intent intent = new Intent(App.getApp(), this.mErrorReportClass); + intent.putExtra("message", t); + intent.putExtra("error", throwableToString(ex)); + App.getApp().startActivity(intent); + System.exit(0); + } catch (Throwable var6) { + var6.printStackTrace(); + } + + } + + public static String throwableToString(Throwable throwable) { + StringWriter sw = new StringWriter(); + PrintWriter pw = new PrintWriter(sw); + throwable.printStackTrace(pw); + return sw.toString(); + } +} diff --git a/app/src/main/java/com/stardust/view/ViewBinder.java b/app/src/main/java/com/stardust/view/ViewBinder.java index 8b1d1a48..68886070 100644 --- a/app/src/main/java/com/stardust/view/ViewBinder.java +++ b/app/src/main/java/com/stardust/view/ViewBinder.java @@ -1,6 +1,7 @@ package com.stardust.view; import android.view.View; +import android.widget.CompoundButton; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; @@ -21,7 +22,31 @@ public class ViewBinder { } Method[] methods = o.getClass().getDeclaredMethods(); for (Method method : methods) { + method.setAccessible(true); bindClick(o, method, findViewById); + bindCheck(o, method, findViewById); + } + } + + private static void bindCheck(final Object o, final Method method, Method findViewById) { + ViewBinding.Check annotation = method.getAnnotation(ViewBinding.Check.class); + if (annotation == null || annotation.value() == 0) + return; + int id = annotation.value(); + try { + CompoundButton button = (CompoundButton) findViewById.invoke(o, id); + button.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() { + @Override + public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) { + try { + method.invoke(o, isChecked); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); + } + } + }); + } catch (IllegalAccessException | InvocationTargetException e) { + e.printStackTrace(); } } @@ -45,7 +70,6 @@ public class ViewBinder { private static void invokeMethod(Object o, Method method) { try { - method.setAccessible(true); method.invoke(o); } catch (IllegalAccessException | InvocationTargetException e) { throw new RuntimeException(e); diff --git a/app/src/main/java/com/stardust/view/ViewBinding.java b/app/src/main/java/com/stardust/view/ViewBinding.java index de739858..a9cc1194 100644 --- a/app/src/main/java/com/stardust/view/ViewBinding.java +++ b/app/src/main/java/com/stardust/view/ViewBinding.java @@ -26,4 +26,10 @@ public @interface ViewBinding { @interface Click { int value(); } + + @Target(ElementType.METHOD) + @Retention(RetentionPolicy.RUNTIME) + @interface Check { + int value(); + } } diff --git a/app/src/main/res/drawable/ic_developer_512.png b/app/src/main/res/drawable/ic_developer_512.png new file mode 100644 index 00000000..2562420e Binary files /dev/null and b/app/src/main/res/drawable/ic_developer_512.png differ diff --git a/app/src/main/res/drawable/ic_email_black_48dp.png b/app/src/main/res/drawable/ic_email_black_48dp.png new file mode 100644 index 00000000..3d136274 Binary files /dev/null and b/app/src/main/res/drawable/ic_email_black_48dp.png differ diff --git a/app/src/main/res/drawable/ic_github_mark.png b/app/src/main/res/drawable/ic_github_mark.png new file mode 100644 index 00000000..92d3c954 Binary files /dev/null and b/app/src/main/res/drawable/ic_github_mark.png differ diff --git a/app/src/main/res/drawable/ic_money_black.png b/app/src/main/res/drawable/ic_money_black.png new file mode 100644 index 00000000..81a01b23 Binary files /dev/null and b/app/src/main/res/drawable/ic_money_black.png differ diff --git a/app/src/main/res/drawable/ic_notifications_green_48dp.png b/app/src/main/res/drawable/ic_notifications_green_48dp.png new file mode 100644 index 00000000..d8d530df Binary files /dev/null and b/app/src/main/res/drawable/ic_notifications_green_48dp.png differ diff --git a/app/src/main/res/drawable/ic_qq.png b/app/src/main/res/drawable/ic_qq.png new file mode 100644 index 00000000..67597fce Binary files /dev/null and b/app/src/main/res/drawable/ic_qq.png differ diff --git a/app/src/main/res/drawable/ic_qq_black.png b/app/src/main/res/drawable/ic_qq_black.png new file mode 100644 index 00000000..00523a9c Binary files /dev/null and b/app/src/main/res/drawable/ic_qq_black.png differ diff --git a/app/src/main/res/drawable/ic_robot_head_green.png b/app/src/main/res/drawable/ic_robot_head_green.png new file mode 100644 index 00000000..56c82ee4 Binary files /dev/null and b/app/src/main/res/drawable/ic_robot_head_green.png differ diff --git a/app/src/main/res/drawable/ic_sdcard_black.png b/app/src/main/res/drawable/ic_sdcard_black.png deleted file mode 100644 index 3e0bf585..00000000 Binary files a/app/src/main/res/drawable/ic_sdcard_black.png and /dev/null differ diff --git a/app/src/main/res/drawable/ic_share_white_48dp.png b/app/src/main/res/drawable/ic_share_white_48dp.png new file mode 100644 index 00000000..e351c7be Binary files /dev/null and b/app/src/main/res/drawable/ic_share_white_48dp.png differ diff --git a/app/src/main/res/layout/activity_about.xml b/app/src/main/res/layout/activity_about.xml new file mode 100644 index 00000000..394f24d7 --- /dev/null +++ b/app/src/main/res/layout/activity_about.xml @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/layout/activity_about_items.xml b/app/src/main/res/layout/activity_about_items.xml new file mode 100644 index 00000000..38125a3e --- /dev/null +++ b/app/src/main/res/layout/activity_about_items.xml @@ -0,0 +1,143 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_error_report.xml b/app/src/main/res/layout/activity_error_report.xml new file mode 100644 index 00000000..2a656d5f --- /dev/null +++ b/app/src/main/res/layout/activity_error_report.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_settings.xml b/app/src/main/res/layout/activity_settings.xml new file mode 100644 index 00000000..172dc6c0 --- /dev/null +++ b/app/src/main/res/layout/activity_settings.xml @@ -0,0 +1,28 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/divider.xml b/app/src/main/res/layout/divider.xml new file mode 100644 index 00000000..6ec7be66 --- /dev/null +++ b/app/src/main/res/layout/divider.xml @@ -0,0 +1,7 @@ + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_slide_menu.xml b/app/src/main/res/layout/fragment_slide_menu.xml index 7e7cab44..d56fa5b2 100644 --- a/app/src/main/res/layout/fragment_slide_menu.xml +++ b/app/src/main/res/layout/fragment_slide_menu.xml @@ -5,6 +5,28 @@ android:layout_height="match_parent" android:orientation="vertical"> + + + + + + + - + android:gravity="center_vertical"> + android:src="@drawable/ic_service_green"/> - + + + + + + + + + + + + + + - - - - - - - - - - - - - - \ No newline at end of file + diff --git a/app/src/main/res/raw/licenses.xml b/app/src/main/res/raw/licenses.xml index 8b61d294..4e0bc1b2 100644 --- a/app/src/main/res/raw/licenses.xml +++ b/app/src/main/res/raw/licenses.xml @@ -12,4 +12,23 @@ Copyright 2008 Google Inc. Apache Software License 2.0 + + DuktapeJava + https://github.com/gubaojian/DuktapeJava + + MIT License + + + 920 Text Editor + https://github.com/jecelyin/920-text-editor-v2 + + Apache Software License 2.0 + + + MarkDown + https://github.com/zzhoujay/Markdown + Copyright (c) 2015 zzhoujay + MIT License + + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 0825a769..17b030b1 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,5 +1,6 @@ 免Root脚本机器人 + Version 1.17.0202 设置 关闭服务 使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。 @@ -32,7 +33,6 @@ 设置 退出 自动操作服务 - Version 1.17.0130 语法与API 关闭所有正在运行的脚本 关于 @@ -41,4 +41,23 @@ 示例:打开朋友圈 示例:打开正在运行的服务(安卓6.0+) 示例:简单计算器 + Copyright©2016 All right reserves. + 星尘幻影 + 946994919 + hybbbb1996@gmail.com + 软件源代码 + 已复制到剪贴板 + 打赏作者 + 邮箱 + https://github.com/hyb1996/NoRootScriptDroid + [免Root脚本机器人]下载地址:https://github.com/hyb1996/NoRootScriptDroid/releases + 脚本辅助服务 + 通知栏显示脚本辅助开关 + 通知栏显示脚本辅助开关 + 其他 + 脚本辅助已开启(点击关闭) + 脚本辅助已关闭(点击开启) + 错误报告 + 大姐姐好 + 再按一次退出程序 diff --git a/app/src/main/res/xml/preferences.xml b/app/src/main/res/xml/preferences.xml new file mode 100644 index 00000000..759efdef --- /dev/null +++ b/app/src/main/res/xml/preferences.xml @@ -0,0 +1,14 @@ + + + + + + + + + + + \ No newline at end of file