fix memory leak
@@ -7,8 +7,8 @@ android {
|
||||
applicationId "com.stardust.scriptdroid"
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 23
|
||||
versionCode 25
|
||||
versionName "1.17.0215"
|
||||
versionCode 27
|
||||
versionName "1.17.0215(2)"
|
||||
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
|
||||
}
|
||||
buildTypes {
|
||||
@@ -46,6 +46,9 @@ repositories {
|
||||
dependencies {
|
||||
compile fileTree(include: ['*.jar'], dir: 'libs')
|
||||
testCompile 'junit:junit:4.12'
|
||||
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5'
|
||||
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
|
||||
testCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5'
|
||||
|
||||
compile 'com.android.support:appcompat-v7:25.1.0'
|
||||
compile 'com.android.support:design:25.1.0'
|
||||
|
||||
@@ -5,6 +5,8 @@ import android.app.Application;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceManager;
|
||||
|
||||
import com.squareup.leakcanary.LeakCanary;
|
||||
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
|
||||
import com.stardust.scriptdroid.droid.runtime.action.ActionPerformAccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
@@ -35,6 +37,12 @@ public class App extends Application {
|
||||
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
if (LeakCanary.isInAnalyzerProcess(this)) {
|
||||
// This process is dedicated to LeakCanary for heap analysis.
|
||||
// You should not init your app in this process.
|
||||
return;
|
||||
}
|
||||
LeakCanary.install(this);
|
||||
if (!BuildConfig.DEBUG)
|
||||
Thread.setDefaultUncaughtExceptionHandler(new CrashHandler(ErrorReportActivity.class));
|
||||
instance = new WeakReference<>(this);
|
||||
@@ -43,9 +51,12 @@ public class App extends Application {
|
||||
initAccessibilityServiceDelegates();
|
||||
}
|
||||
|
||||
|
||||
private void initAccessibilityServiceDelegates() {
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(100, ActionPerformAccessibilityDelegate.class);
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(200, AccessibilityRecorderDelegate.getInstance());
|
||||
AccessibilityWatchDogService.addDelegateIfNeeded(300, BoundsAssistant.class);
|
||||
|
||||
}
|
||||
|
||||
private void registerActivityLifecycleCallback() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.stardust.scriptdroid.bounds_assist;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.graphics.Rect;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
@@ -10,15 +11,16 @@ import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.service.AccessibilityDelegate;
|
||||
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/2/4.
|
||||
*/
|
||||
|
||||
public class BoundsAssistant {
|
||||
public static final String KEY_BOUNDS_ASSIST_ENABLE = "ASSIST_MODE_ENABLE";
|
||||
public class BoundsAssistant implements AccessibilityDelegate {
|
||||
|
||||
public static final String KEY_BOUNDS_ASSIST_ENABLE = "ASSIST_MODE_ENABLE";
|
||||
|
||||
private static boolean assistModeEnable;
|
||||
private static BoundsAssistClipList boundsAssistClipList = SharedPrefBoundsAssistClipList.getInstance();
|
||||
@@ -43,7 +45,7 @@ public class BoundsAssistant {
|
||||
.show();
|
||||
}
|
||||
|
||||
public static void performAssistance(AccessibilityEvent event) {
|
||||
private static void performAssistance(AccessibilityEvent event) {
|
||||
if (!assistModeEnable) {
|
||||
return;
|
||||
}
|
||||
@@ -59,6 +61,12 @@ public class BoundsAssistant {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onAccessibilityEvent(AccessibilityService service, AccessibilityEvent event) {
|
||||
performAssistance(event);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static Rect getBoundsInScreen(AccessibilityNodeInfo nodeInfo) {
|
||||
Rect rect = new Rect();
|
||||
nodeInfo.getBoundsInScreen(rect);
|
||||
@@ -80,4 +88,5 @@ public class BoundsAssistant {
|
||||
assistModeEnable = PreferenceManager.getDefaultSharedPreferences(App.getApp()).getBoolean(KEY_BOUNDS_ASSIST_ENABLE, false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import com.stardust.scriptdroid.file.FileUtils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.Serializable;
|
||||
|
||||
import timber.log.Timber;
|
||||
|
||||
@@ -30,7 +31,7 @@ public class Droid {
|
||||
|
||||
public static final String UI = "\"ui\";";
|
||||
|
||||
public interface OnRunFinishedListener {
|
||||
public interface OnRunFinishedListener extends Serializable {
|
||||
void onRunFinished(Object result, Exception e);
|
||||
}
|
||||
|
||||
|
||||
@@ -16,44 +16,52 @@ import static com.stardust.scriptdroid.droid.Droid.JAVA_SCRIPT_ENGINE;
|
||||
|
||||
public class ScriptExecuteActivity extends Activity {
|
||||
|
||||
private static String script;
|
||||
private static Droid.OnRunFinishedListener onRunFinishedListener;
|
||||
private static RunningConfig runningConfig;
|
||||
private static final String EXTRA_SCRIPT = "EXTRA_SCRIPT";
|
||||
private static final String EXTRA_ON_RUN_FINISHED_LISTENER = "EXTRA_ON_RUN_FINISHED_LISTENER";
|
||||
private Object mResult;
|
||||
private String mScript;
|
||||
private Droid.OnRunFinishedListener mOnRunFinishedListener;
|
||||
|
||||
|
||||
public static void runScript(String script, Droid.OnRunFinishedListener listener, RunningConfig config) {
|
||||
ScriptExecuteActivity.script = script;
|
||||
ScriptExecuteActivity.onRunFinishedListener = listener;
|
||||
ScriptExecuteActivity.runningConfig = config;
|
||||
App.getApp().startActivity(new Intent(App.getApp(), ScriptExecuteActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));
|
||||
App.getApp().startActivity(new Intent(App.getApp(), ScriptExecuteActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(EXTRA_SCRIPT, script)
|
||||
.putExtra(EXTRA_ON_RUN_FINISHED_LISTENER, listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
handleIntent(getIntent());
|
||||
runScript();
|
||||
}
|
||||
|
||||
private void handleIntent(Intent intent) {
|
||||
mScript = intent.getStringExtra(EXTRA_SCRIPT);
|
||||
mOnRunFinishedListener = (Droid.OnRunFinishedListener) intent.getSerializableExtra(EXTRA_ON_RUN_FINISHED_LISTENER);
|
||||
}
|
||||
|
||||
private void runScript() {
|
||||
JAVA_SCRIPT_ENGINE.set("activity", Activity.class, this);
|
||||
try {
|
||||
mResult = JAVA_SCRIPT_ENGINE.execute(script);
|
||||
mResult = JAVA_SCRIPT_ENGINE.execute(mScript);
|
||||
} catch (Exception e) {
|
||||
onRunFinishedListener.onRunFinished(null, e);
|
||||
mOnRunFinishedListener.onRunFinished(null, e);
|
||||
finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
onRunFinishedListener.onRunFinished(mResult, null);
|
||||
mOnRunFinishedListener.onRunFinished(mResult, null);
|
||||
super.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
JAVA_SCRIPT_ENGINE.set("activity", Activity.class, null);
|
||||
JAVA_SCRIPT_ENGINE.removeAndDestroy(Thread.currentThread());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -29,6 +29,7 @@ public class ActionRecordNotificationHandleService extends Service {
|
||||
private static final int ACTION_STOP = 17771;
|
||||
private static final int ACTION_START_OR_PAUSE = 17772;
|
||||
private static final int ACTION_DELETE = 17773;
|
||||
private static final int ACTION_REDO = 17774;
|
||||
|
||||
public static PendingIntent getStartOrPauseIntent() {
|
||||
Intent intent = new Intent(App.getApp(), ActionRecordNotificationHandleService.class)
|
||||
@@ -51,6 +52,15 @@ public class ActionRecordNotificationHandleService extends Service {
|
||||
return PendingIntent.getService(App.getApp(), ACTION_DELETE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
|
||||
public static PendingIntent getRedoIntent() {
|
||||
Intent intent = new Intent(App.getApp(), ActionRecordNotificationHandleService.class)
|
||||
.putExtra(EXTRA_INTENT_VALID, true)
|
||||
.putExtra(EXTRA_ACTION, ACTION_REDO);
|
||||
return PendingIntent.getService(App.getApp(), ACTION_REDO, intent, PendingIntent.FLAG_UPDATE_CURRENT);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
boolean intentValid = intent.getBooleanExtra(EXTRA_INTENT_VALID, false);
|
||||
@@ -65,16 +75,23 @@ public class ActionRecordNotificationHandleService extends Service {
|
||||
switch (action) {
|
||||
case ACTION_STOP:
|
||||
stopRecord();
|
||||
collapseNotificationBar();
|
||||
break;
|
||||
case ACTION_START_OR_PAUSE:
|
||||
startOrPauseRecord();
|
||||
collapseNotificationBar();
|
||||
break;
|
||||
case ACTION_DELETE:
|
||||
ActionRecordSwitchNotification.cancelNotification();
|
||||
stopRecordIfNeeded();
|
||||
break;
|
||||
case ACTION_REDO:
|
||||
redoRecord();
|
||||
break;
|
||||
}
|
||||
collapseNotificationBar();
|
||||
}
|
||||
|
||||
|
||||
private void collapseNotificationBar() {
|
||||
sendBroadcast(new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS));
|
||||
}
|
||||
@@ -115,9 +132,18 @@ public class ActionRecordNotificationHandleService extends Service {
|
||||
}
|
||||
}
|
||||
|
||||
private void redoRecord() {
|
||||
if (AccessibilityRecorderDelegate.getInstance().getState() != STOPPED) {
|
||||
AccessibilityRecorderDelegate.getInstance().stopRecord();
|
||||
ActionRecordSwitchView.getInstance().setState(STOPPED);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -33,4 +33,9 @@ public class ActionRecordSwitchNotification {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.notify(NOTIFY_ID, notification);
|
||||
}
|
||||
|
||||
public static void cancelNotification() {
|
||||
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
|
||||
notificationManager.cancel(NOTIFY_ID);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,5 +50,7 @@ public class ActionRecordSwitchView extends RemoteViews {
|
||||
private void setUpOnClick() {
|
||||
setOnClickPendingIntent(R.id.stop, ActionRecordNotificationHandleService.getStopIntent());
|
||||
setOnClickPendingIntent(R.id.start_or_pause, ActionRecordNotificationHandleService.getStartOrPauseIntent());
|
||||
setOnClickPendingIntent(R.id.close, ActionRecordNotificationHandleService.getDeleteIntent());
|
||||
setOnClickPendingIntent(R.id.redo, ActionRecordNotificationHandleService.getRedoIntent());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,6 +62,8 @@ public class ActionRecorder {
|
||||
@Override
|
||||
public void onAccessibilityEvent(AccessibilityEvent event, StringBuilder sb) {
|
||||
AccessibilityNodeInfo source = event.getSource();
|
||||
if (source == null)
|
||||
return;
|
||||
String bounds = boundsToString(getBoundsInScreen(source));
|
||||
source.recycle();
|
||||
onAccessibilityEvent(event, bounds, sb);
|
||||
|
||||
@@ -8,6 +8,7 @@ import android.view.accessibility.AccessibilityEvent;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
import java.util.TreeMap;
|
||||
@@ -21,7 +22,7 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
private static final String TAG = "AccessibilityWatchDog";
|
||||
|
||||
private static final SortedMap<Integer, AccessibilityDelegate> mDelegates = new TreeMap<>();
|
||||
private static AccessibilityWatchDogService instance;
|
||||
private static WeakReference<AccessibilityWatchDogService> instance;
|
||||
|
||||
public static void addDelegate(AccessibilityDelegate delegate, int uniquePriority) {
|
||||
synchronized (mDelegates) {
|
||||
@@ -62,7 +63,9 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
}
|
||||
|
||||
public static AccessibilityWatchDogService getInstance() {
|
||||
return instance;
|
||||
if (instance == null)
|
||||
return null;
|
||||
return instance.get();
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -85,12 +88,12 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
super.onServiceConnected();
|
||||
// FIXME: 2017/2/12 有时在无障碍中开启服务后这里不会调用服务也不会运行,安卓的BUG???
|
||||
Log.v(TAG, "onServiceConnected");
|
||||
instance = this;
|
||||
instance = new WeakReference<>(this);
|
||||
}
|
||||
|
||||
public static void disable() {
|
||||
if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
instance.disableSelf();
|
||||
if (instance != null && instance.get() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
instance.get().disableSelf();
|
||||
} else {
|
||||
AccessibilityServiceUtils.goToAccessibilitySetting(App.getApp());
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
package com.stardust.scriptdroid.ui.edit;
|
||||
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.os.Bundle;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.design.widget.Snackbar;
|
||||
@@ -18,6 +20,7 @@ import com.jecelyin.editor.v2.common.SaveListener;
|
||||
import com.jecelyin.editor.v2.ui.EditorDelegate;
|
||||
import com.jecelyin.editor.v2.view.EditorView;
|
||||
import com.jecelyin.editor.v2.view.menu.MenuDef;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.droid.Droid;
|
||||
@@ -40,6 +43,18 @@ public class EditActivity extends Editor920Activity {
|
||||
|
||||
private static final String KEY_EDIT_ACTIVITY_FIRST_USE = "KEY_EDIT_ACTIVITY_FIRST_USE";
|
||||
|
||||
private static final String ACTION_ON_RUN_FINISHED = "ACTION_ON_RUN_FINISHED";
|
||||
private static final String EXTRA_EXCEPTION = "EXTRA_EXCEPTION";
|
||||
|
||||
private static final Droid.OnRunFinishedListener ON_RUN_FINISHED_LISTENER = new Droid.OnRunFinishedListener() {
|
||||
|
||||
@Override
|
||||
public void onRunFinished(Object result, Exception e) {
|
||||
App.getApp().sendBroadcast(new Intent(ACTION_ON_RUN_FINISHED)
|
||||
.putExtra(EXTRA_EXCEPTION, e));
|
||||
}
|
||||
};
|
||||
|
||||
public static void editFile(Context context, String path) {
|
||||
editFile(context, null, path);
|
||||
}
|
||||
@@ -57,12 +72,24 @@ public class EditActivity extends Editor920Activity {
|
||||
private DrawerLayout mDrawerLayout;
|
||||
private EditorDelegate mEditorDelegate;
|
||||
private SparseArray<ToolbarMenuItem> mMenuMap;
|
||||
private BroadcastReceiver mOnRunFinishedReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getAction().equals(ACTION_ON_RUN_FINISHED)) {
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_NORMAL);
|
||||
Exception e = (Exception) intent.getSerializableExtra(EXTRA_EXCEPTION);
|
||||
if (e != null)
|
||||
Snackbar.make(mView, getString(R.string.text_error) + ": " + e.getMessage(), Snackbar.LENGTH_INDEFINITE).show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public void onCreate(Bundle b) {
|
||||
super.onCreate(b);
|
||||
handleIntent();
|
||||
setUpUI();
|
||||
setUpEditor();
|
||||
registerReceiver(mOnRunFinishedReceiver, new IntentFilter(ACTION_ON_RUN_FINISHED));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -175,19 +202,7 @@ public class EditActivity extends Editor920Activity {
|
||||
private void run() {
|
||||
Snackbar.make(mView, R.string.text_start_running, Snackbar.LENGTH_SHORT).show();
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_DISABLED);
|
||||
Droid.getInstance().runScriptFile(mFile, new Droid.OnRunFinishedListener() {
|
||||
@Override
|
||||
public void onRunFinished(Object result, final Exception e) {
|
||||
runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
setMenuStatus(R.id.run, MenuDef.STATUS_NORMAL);
|
||||
if (e != null)
|
||||
Snackbar.make(mView, getString(R.string.text_error) + ": " + e.getMessage(), Snackbar.LENGTH_INDEFINITE).show();
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
Droid.getInstance().runScriptFile(mFile, ON_RUN_FINISHED_LISTENER);
|
||||
}
|
||||
|
||||
@ViewBinding.Click(R.id.undo)
|
||||
@@ -261,4 +276,10 @@ public class EditActivity extends Editor920Activity {
|
||||
public void doCommand(Command command) {
|
||||
mEditorDelegate.doCommand(command);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
unregisterReceiver(mOnRunFinishedReceiver);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -125,7 +125,7 @@ public class IssueReportActivity extends IssueReporterActivity {
|
||||
|
||||
@Override
|
||||
protected String getGuestToken() {
|
||||
return "f32d789662645640ff22e240b80f5d76117181a1";
|
||||
return "899ce4e559f7c3fad7a3a34a05777724758550de";
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ public class MainActivity extends BaseActivity implements FileChooserDialog.File
|
||||
|
||||
public static void onActionRecordStopped(Context context, String script) {
|
||||
Intent intent = new Intent(context, MainActivity.class)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
|
||||
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
.putExtra(EXTRA_ACTION, ACTION_ON_ACTION_RECORD_STOPPED)
|
||||
.putExtra(ARGUMENT_SCRIPT, script);
|
||||
context.startActivity(intent);
|
||||
|
||||
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 4.7 KiB |
|
Before Width: | Height: | Size: 10 KiB |
BIN
app/src/main/res/drawable/ic_close_gray600_48dp.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.1 KiB |
|
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 1.8 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 779 B |
|
Before Width: | Height: | Size: 6.5 KiB After Width: | Height: | Size: 3.2 KiB |
|
Before Width: | Height: | Size: 7.9 KiB |
|
Before Width: | Height: | Size: 92 KiB After Width: | Height: | Size: 3.3 KiB |
|
Before Width: | Height: | Size: 7.0 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 2.2 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 1.9 KiB |
|
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 1.2 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 1.5 KiB |
BIN
app/src/main/res/drawable/ic_redo_gray600.png
Normal file
|
After Width: | Height: | Size: 2.1 KiB |
|
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 1.5 KiB |
|
Before Width: | Height: | Size: 32 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 23 KiB After Width: | Height: | Size: 6.0 KiB |
|
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 3.9 KiB |
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 2.7 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.8 KiB |
|
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 1.7 KiB |
|
Before Width: | Height: | Size: 5.8 KiB After Width: | Height: | Size: 6.7 KiB |
|
Before Width: | Height: | Size: 58 KiB |
BIN
app/src/main/res/drawable/slide_menu_img_200px.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
@@ -18,7 +18,7 @@
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:scaleType="fitXY"
|
||||
android:src="@drawable/slide_menu_img"/>
|
||||
android:src="@drawable/slide_menu_img_200px"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/version"
|
||||
|
||||
@@ -64,5 +64,55 @@
|
||||
android:textSize="12sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/redo"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="4dp"
|
||||
android:background="@drawable/btn_selector"
|
||||
android:clickable="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="4dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:padding="5dp"
|
||||
android:src="@drawable/ic_redo_gray600"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_re_record"
|
||||
android:textColor="#777777"
|
||||
android:textSize="12sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/close"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_margin="4dp"
|
||||
android:background="@drawable/btn_selector"
|
||||
android:clickable="true"
|
||||
android:gravity="center_horizontal"
|
||||
android:orientation="vertical"
|
||||
android:padding="4dp">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="30dp"
|
||||
android:layout_height="30dp"
|
||||
android:src="@drawable/ic_close_gray600_48dp"/>
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:text="@string/text_close"
|
||||
android:textColor="#777777"
|
||||
android:textSize="12sp"/>
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
||||
@@ -115,4 +115,6 @@
|
||||
<string name="text_need_enable_accessibility_service">需要打开\"自动操作服务“才能录制脚本</string>
|
||||
<string name="text_join_qq_group">加入QQ交流群</string>
|
||||
<string name="text_qq_group_id_copied">已复制群号到剪贴板</string>
|
||||
<string name="text_close">关闭</string>
|
||||
<string name="text_re_record">重新录制</string>
|
||||
</resources>
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
package com.stardust.scriptdroid;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* Example local unit test, which will execute on the development machine (host).
|
||||
@@ -15,69 +14,18 @@ import java.util.TreeMap;
|
||||
public class ExampleUnitTest {
|
||||
@Test
|
||||
public void testSync() throws Exception {
|
||||
final Sync sync = new Sync();
|
||||
//sync.print(11);
|
||||
add(sync, 11, 123);
|
||||
//Thread.sleep(1);
|
||||
sync.print(11);
|
||||
add(sync, 11, 456);
|
||||
sync.print(11);
|
||||
}
|
||||
|
||||
private void add(final Sync sync, final int key, final int i) {
|
||||
new Thread(new Runnable() {
|
||||
Bundle bundle = new Bundle();
|
||||
bundle.putSerializable("xxx", new XXX() {
|
||||
@Override
|
||||
public void run() {
|
||||
sync.add(key, i);
|
||||
void run() {
|
||||
System.out.println("xxx");
|
||||
}
|
||||
}).start();
|
||||
});
|
||||
((XXX) bundle.getSerializable("xxx")).run();
|
||||
}
|
||||
|
||||
private static class Sync {
|
||||
private static abstract class XXX implements Serializable {
|
||||
|
||||
private final Map<Integer, List<Integer>> mMap = new TreeMap<>();
|
||||
|
||||
Sync() {
|
||||
for (int i = 0; i < 10; i++) {
|
||||
List<Integer> list = new ArrayList<>();
|
||||
for (int j = 0; j < 10; j++) {
|
||||
list.add(j * i);
|
||||
}
|
||||
mMap.put(i, list);
|
||||
}
|
||||
}
|
||||
|
||||
public Sync add(int key, int i) {
|
||||
synchronized (mMap) {
|
||||
List<Integer> list = ensureList(key);
|
||||
list.add(i);
|
||||
System.out.println("add:" + key + " " + i);
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
private List<Integer> ensureList(int key) {
|
||||
List<Integer> list = mMap.get(key);
|
||||
if (list == null) {
|
||||
list = new ArrayList<>();
|
||||
mMap.put(key, list);
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
public void print(int key) {
|
||||
synchronized (mMap) {
|
||||
List<Integer> list = mMap.get(key);
|
||||
System.out.print(key + ":");
|
||||
if (list == null) {
|
||||
System.out.print("null");
|
||||
} else {
|
||||
for (Integer i : list) {
|
||||
System.out.print(i + " ");
|
||||
}
|
||||
}
|
||||
System.out.println();
|
||||
}
|
||||
}
|
||||
abstract void run();
|
||||
}
|
||||
}
|
||||