add: about page, settings, notification switch

This commit is contained in:
hyb1996
2017-02-03 10:41:23 +08:00
parent 636ce6d889
commit 5640b47663
47 changed files with 1392 additions and 307 deletions

5
.idea/misc.xml generated
View File

@@ -2,9 +2,10 @@
<project version="4">
<component name="EntryPointsManager">
<entry_points version="2.0" />
<list size="2">
<list size="3">
<item index="0" class="java.lang.String" itemvalue="com.stardust.view.ViewBind.Click" />
<item index="1" class="java.lang.String" itemvalue="com.stardust.view.ViewBinding.Click" />
<item index="1" class="java.lang.String" itemvalue="com.stardust.view.ViewBinding.Check" />
<item index="2" class="java.lang.String" itemvalue="com.stardust.view.ViewBinding.Click" />
</list>
</component>
<component name="NullableNotNullManager">

View File

@@ -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')

View File

@@ -72,9 +72,90 @@
</provider>
<activity android:name=".EditActivity"/>
<activity android:name=".DocumentActivity"/>
<activity android:name=".AboutActivity"/>
<activity android:name=".SettingsActivity"/>
<activity android:name=".ErrorReportActivity"/>
<service android:name=".AssistModeSwitchService"/>
<activity
android:name="com.stardust.EditAndRunIntentActivity"
android:icon="@drawable/ic_edit_green_48dp"
android:label="编辑与运行脚本">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.EDIT"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:mimeType="application/x-*"/>
<data android:mimeType="application/postscript"/>
<data android:mimeType="application/plain"/>
<data android:mimeType="application/x-javascript"/>
<data android:mimeType="text/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="com.googlecode.android_scripting.action.EDIT_SCRIPT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
<activity
android:name=".ImportIntentActivity"
android:icon="@drawable/ic_folder_open_outline_green"
android:label="导入脚本文件">
<intent-filter>
<action android:name="android.intent.action.VIEW"/>
<action android:name="android.intent.action.EDIT"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.BROWSABLE"/>
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:mimeType="application/x-*"/>
<data android:mimeType="application/postscript"/>
<data android:mimeType="application/plain"/>
<data android:mimeType="application/x-javascript"/>
<data android:mimeType="text/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="text/*"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEARCH"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
<intent-filter>
<action android:name="com.googlecode.android_scripting.action.EDIT_SCRIPT"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
</application>
</manifest>

View File

@@ -0,0 +1,4 @@
toast("大姐姐好")
for(var i = 0; i < 10; i++){
toast("大姐姐今年有" + i + "块钱~");
}

View File

@@ -1,5 +1,3 @@
launchApp("微信");
sleep(500);
click("发现");
sleep(500);
click("朋友圈");
while(!click("发现"));
while(!click("朋友圈"));

View File

@@ -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);
}
}

View File

@@ -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;
}
}
}

View File

@@ -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();
}
}

View File

@@ -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;
}
}

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View File

@@ -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();
}
}
}

View File

@@ -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));
}
}

View File

@@ -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();
}
}

View File

@@ -18,7 +18,7 @@ public class NonUiInitializer {
private static final Map<String, Integer> SAMPLES = new MapEntries<String, Integer>()
.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();
}

View File

@@ -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<String, Runnable> 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<String, Runnable>()
.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();
}
}
}

View File

@@ -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) {

View File

@@ -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;
}
}

View File

@@ -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

View File

@@ -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<Pair<DuktapeEngine, Thread>> mDuktapeEngineList = new ArrayList<>();
private static final String INIT_SCRIPT;
private Map<String, Object> 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<String, Object> variable : mVariableMap.entrySet()) {
duktapeEngine.put(variable.getKey(), variable.getValue());
}
}
private void remove(DuktapeEngine duktapeEngine) {
duktapeEngine.destory();
synchronized (mDuktapeEngineList) {
Iterator<Pair<DuktapeEngine, Thread>> iterator = mDuktapeEngineList.iterator();
while (iterator.hasNext()) {
Pair<DuktapeEngine, Thread> 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 <T> void set(String varName, Class<T> 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<DuktapeEngine, Thread> pair : mDuktapeEngineList) {
stop(pair.first, pair.second);
}
} catch (Throwable throwable) {
throwable.printStackTrace();
n = mDuktapeEngineList.size();
mDuktapeEngineList.clear();
}
super.finalize();
return n;
}
}

View File

@@ -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<Pair<DuktapeEngine, Thread>> mDuktapeEngineList = new ArrayList<>();
private static final String INIT_SCRIPT;
private Map<String, Object> 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<String, Object> variable : mVariableMap.entrySet()) {
duktapeEngine.put(variable.getKey(), variable.getValue());
}
}
private void remove(DuktapeEngine duktapeEngine) {
duktapeEngine.destory();
synchronized (mDuktapeEngineList) {
Iterator<Pair<DuktapeEngine, Thread>> iterator = mDuktapeEngineList.iterator();
while (iterator.hasNext()) {
Pair<DuktapeEngine, Thread> 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 <T> void set(String varName, Class<T> c, T value) {
mVariableMap.put(varName, value);
}
@Override
public int stopAll() {
int n;
synchronized (mDuktapeEngineList) {
for (Pair<DuktapeEngine, Thread> pair : mDuktapeEngineList) {
stop(pair.first, pair.second);
}
n = mDuktapeEngineList.size();
mDuktapeEngineList.clear();
}
return n;
}
}

View File

@@ -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();
}
}
}
}

View File

@@ -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"));
}
}

View File

@@ -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);
}
}

View File

@@ -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());
}
}

View File

@@ -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();
}
}

View File

@@ -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);

View File

@@ -26,4 +26,10 @@ public @interface ViewBinding {
@interface Click {
int value();
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@interface Check {
int value();
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 938 B

View File

@@ -0,0 +1,94 @@
<?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f9f9f9"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"
app:title="@string/text_about"/>
</android.support.design.widget.AppBarLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="16dp"
android:orientation="vertical">
<RelativeLayout
android:id="@+id/icon_container"
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@android:color/white"
android:clickable="true"
android:foreground="?selectableItemBackgroundBorderless">
<ImageView
android:id="@+id/icon"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_centerInParent="true"
android:src="@drawable/script_droid"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="@id/icon"
android:layout_centerHorizontal="true"
android:layout_marginTop="16dp"
android:gravity="center"
android:text="@string/version"
android:textColor="#777777"
android:textSize="14sp"/>
</RelativeLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<include layout="@layout/activity_about_items"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:gravity="center"
android:text="@string/copyright"
android:textColor="#777777"
android:textSize="14sp"/>
</RelativeLayout>
</LinearLayout>
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/share"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:clickable="true"
android:src="@drawable/ic_share_white_48dp"
app:layout_anchor="@id/icon_container"
app:layout_anchorGravity="bottom|right|end"/>
</android.support.design.widget.CoordinatorLayout>

View File

@@ -0,0 +1,143 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="12dp"
android:background="@android:color/white"
android:orientation="vertical">
<LinearLayout
android:id="@+id/developer"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_developer_512"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/developer"
android:textColor="@android:color/secondary_text_light"
android:textSize="16sp"/>
</LinearLayout>
<include layout="@layout/divider"/>
<LinearLayout
android:id="@+id/github"
android:layout_width="match_parent"
android:layout_height="52dp"
android:clickable="true"
android:foreground="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_github_mark"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/github"
android:textColor="@android:color/secondary_text_light"
android:textIsSelectable="true"
android:textSize="16sp"/>
</LinearLayout>
<include layout="@layout/divider"/>
<LinearLayout
android:id="@+id/email"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_email_black_48dp"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/email"
android:textColor="@android:color/secondary_text_light"
android:textIsSelectable="true"
android:textSize="16sp"/>
</LinearLayout>
<include layout="@layout/divider"/>
<LinearLayout
android:id="@+id/qq"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_qq_black"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/qq"
android:textColor="@android:color/secondary_text_light"
android:textIsSelectable="true"
android:textSize="16sp"/>
</LinearLayout>
<include layout="@layout/divider"/>
<LinearLayout
android:id="@+id/donate"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:clickable="true"
android:gravity="center_vertical"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_marginRight="16dp"
android:src="@drawable/ic_money_black"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/donate_developer"
android:textColor="@android:color/secondary_text_light"
android:textSize="16sp"/>
</LinearLayout>
<include layout="@layout/divider"/>
</LinearLayout>

View File

@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
</LinearLayout>

View File

@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay"/>
</android.support.design.widget.AppBarLayout>
<FrameLayout
android:id="@+id/fragment_setting"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<View xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#e4e4e4"
android:paddingEnd="16dp"
android:paddingStart="16dp"/>

View File

@@ -5,6 +5,28 @@
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:id="@+id/syntax_and_api"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_margin="16dp"
android:src="@drawable/ic_js"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/text_syntax_and_api"
android:textColor="@android:color/primary_text_light"/>
</LinearLayout>
<RelativeLayout
android:id="@+id/auto_operate_service"
android:layout_width="match_parent"
@@ -39,27 +61,71 @@
</RelativeLayout>
<LinearLayout
android:id="@+id/syntax_and_api"
<RelativeLayout
android:id="@+id/assist_service"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal">
android:gravity="center_vertical">
<ImageView
android:id="@+id/icon_assist_service"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_margin="16dp"
android:src="@drawable/ic_js"/>
android:src="@drawable/ic_service_green"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@id/icon_assist_service"
android:gravity="center"
android:text="@string/text_syntax_and_api"
android:text="@string/text_assist_service"
android:textColor="@android:color/primary_text_light"/>
</LinearLayout>
<android.support.v7.widget.SwitchCompat
android:id="@+id/sw_assist_service"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginRight="16dp"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/assist_service_notification"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical">
<ImageView
android:id="@+id/icon_assist_service_notification"
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentLeft="true"
android:layout_margin="16dp"
android:src="@drawable/ic_notifications_green_48dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_toRightOf="@id/icon_assist_service_notification"
android:gravity="center"
android:text="@string/text_assist_service_notification"
android:textColor="@android:color/primary_text_light"/>
<android.support.v7.widget.SwitchCompat
android:id="@+id/sw_assist_service_notification"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_centerVertical="true"
android:layout_marginRight="16dp"/>
</RelativeLayout>
<LinearLayout
android:id="@+id/stop_all_running_scripts"
@@ -83,47 +149,4 @@
android:textColor="@android:color/primary_text_light"/>
</LinearLayout>
<LinearLayout
android:id="@+id/about_app"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_margin="16dp"
android:src="@drawable/ic_about_us_green_100px"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/text_about"
android:textColor="@android:color/primary_text_light"/>
</LinearLayout>
<LinearLayout
android:id="@+id/licenses"
android:layout_width="match_parent"
android:layout_height="52dp"
android:background="?selectableItemBackground"
android:gravity="center_vertical"
android:orientation="horizontal">
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_margin="16dp"
android:src="@drawable/ic_license_green"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:gravity="center"
android:text="@string/text_licenses"
android:textColor="@android:color/primary_text_light"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -12,4 +12,23 @@
<copyright>Copyright 2008 Google Inc.</copyright>
<license>Apache Software License 2.0</license>
</notice>
<notice>
<name>DuktapeJava</name>
<url>https://github.com/gubaojian/DuktapeJava</url>
<copyright/>
<license>MIT License</license>
</notice>
<notice>
<name>920 Text Editor</name>
<url>https://github.com/jecelyin/920-text-editor-v2</url>
<copyright/>
<license>Apache Software License 2.0</license>
</notice>
<notice>
<name>MarkDown</name>
<url>https://github.com/zzhoujay/Markdown</url>
<copyright>Copyright (c) 2015 zzhoujay</copyright>
<license>MIT License</license>
</notice>
</notices>

View File

@@ -1,5 +1,6 @@
<resources>
<string name="app_name">免Root脚本机器人</string>
<string name="version">Version 1.17.0202</string>
<string name="action_settings">设置</string>
<string name="action_disable_service">关闭服务</string>
<string name="text_accessibility_service_description">使脚本自动操作(点击、长按、滑动等)所需,若关闭则只能执行不涉及自动操作的脚本。</string>
@@ -32,7 +33,6 @@
<string name="text_setting">设置</string>
<string name="text_exit">退出</string>
<string name="text_auto_operate_service">自动操作服务</string>
<string name="version">Version 1.17.0130</string>
<string name="text_syntax_and_api">语法与API</string>
<string name="text_close_all_running_scripts">关闭所有正在运行的脚本</string>
<string name="text_about">关于</string>
@@ -41,4 +41,23 @@
<string name="text_sample_open_what_moment">示例:打开朋友圈</string>
<string name="text_sample_open_running_services">示例:打开正在运行的服务(安卓6.0+)</string>
<string name="text_sample_simple_calculator">示例:简单计算器</string>
<string name="copyright">Copyright©2016 All right reserves.</string>
<string name="developer">星尘幻影</string>
<string name="qq">946994919</string>
<string name="email">hybbbb1996@gmail.com</string>
<string name="github">软件源代码</string>
<string name="text_already_copy_to_clip">已复制到剪贴板</string>
<string name="donate_developer">打赏作者</string>
<string name="text_email">邮箱</string>
<string name="my_github">https://github.com/hyb1996/NoRootScriptDroid</string>
<string name="share_app">[免Root脚本机器人]下载地址https://github.com/hyb1996/NoRootScriptDroid/releases</string>
<string name="text_assist_service">脚本辅助服务</string>
<string name="text_assist_serivce_notification">通知栏显示脚本辅助开关</string>
<string name="text_assist_service_notification">通知栏显示脚本辅助开关</string>
<string name="text_others">其他</string>
<string name="text_assist_mode_enabled">脚本辅助已开启(点击关闭)</string>
<string name="text_assist_mode_disabled">脚本辅助已关闭(点击开启)</string>
<string name="text_error_report">错误报告</string>
<string name="text_sample_hello_big_sister">大姐姐好</string>
<string name="text_press_again_to_exit">再按一次退出程序</string>
</resources>

View File

@@ -0,0 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:title="@string/text_about">
<Preference
android:title="@string/text_about"/>
<Preference
android:title="@string/text_licenses"/>
</PreferenceCategory>
</PreferenceScreen>