Attempt to fix selector memeory leak. Add update checker
This commit is contained in:
@@ -13,6 +13,7 @@ import com.stardust.app.VolumeChangeObserver;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
|
||||
import com.stardust.scriptdroid.tool.CrashHandler;
|
||||
import com.stardust.scriptdroid.tool.UpdateChecker;
|
||||
import com.stardust.scriptdroid.ui.error.ErrorReportActivity;
|
||||
import com.stardust.theme.ThemeColor;
|
||||
import com.stardust.theme.ThemeColorManager;
|
||||
|
||||
@@ -16,7 +16,7 @@ public class Pref {
|
||||
private static SharedPreferences.OnSharedPreferenceChangeListener onSharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener() {
|
||||
@Override
|
||||
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
|
||||
if (key.equals(App.getResString(R.string.key_run_mode))) {
|
||||
if (key.equals(getString(R.string.key_run_mode))) {
|
||||
AutoJs.getInstance().getCommandHost().setRunMode(getRunModeFromValue(sharedPreferences.getString(key, null)));
|
||||
}
|
||||
}
|
||||
@@ -33,14 +33,10 @@ public class Pref {
|
||||
}
|
||||
}
|
||||
|
||||
public static SharedPreferences def() {
|
||||
private static SharedPreferences def() {
|
||||
return PreferenceManager.getDefaultSharedPreferences(App.getApp());
|
||||
}
|
||||
|
||||
public static boolean isFirstEnableAssistMode() {
|
||||
return getDisposableBoolean("isFirstEnableAssistMode", true);
|
||||
}
|
||||
|
||||
private static boolean getDisposableBoolean(String key, boolean defaultValue) {
|
||||
boolean b = DISPOSABLE_BOOLEAN.getBoolean(key, defaultValue);
|
||||
if (b == defaultValue) {
|
||||
@@ -65,9 +61,20 @@ public class Pref {
|
||||
return def().getBoolean(getString(R.string.key_use_volume_control_running), false);
|
||||
}
|
||||
|
||||
public static String getStartRecordTrigger() {
|
||||
return def().getString(getString(R.string.key_start_record_trigger), null);
|
||||
}
|
||||
|
||||
public static String getStopRecordTrigger() {
|
||||
return def().getString(getString(R.string.key_stop_record_trigger), null);
|
||||
}
|
||||
|
||||
public static boolean enableAccessibilityServiceByRoot() {
|
||||
return def().getBoolean(getString(R.string.key_enable_accessibility_service_by_root), false);
|
||||
}
|
||||
|
||||
private static String getString(int id) {
|
||||
return App.getApp().getString(id);
|
||||
return App.getResString(id);
|
||||
}
|
||||
|
||||
public static int MaxTextLengthForCodeCompletion() {
|
||||
@@ -85,4 +92,9 @@ public class Pref {
|
||||
static {
|
||||
def().registerOnSharedPreferenceChangeListener(onSharedPreferenceChangeListener);
|
||||
}
|
||||
|
||||
public static boolean isEditActivityFirstUsing() {
|
||||
return getDisposableBoolean("Still Love Eating 17.4.6", true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -63,16 +63,6 @@ public class AutoJs implements AccessibilityBridge {
|
||||
.build();
|
||||
ScriptEngineService.setInstance(mScriptEngineService);
|
||||
addAccessibilityServiceDelegates();
|
||||
getGlobalFunctions();
|
||||
}
|
||||
|
||||
private void getGlobalFunctions() {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mScriptEngineService.getGlobalFunctions();
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
|
||||
private void addAccessibilityServiceDelegates() {
|
||||
@@ -114,8 +104,8 @@ public class AutoJs implements AccessibilityBridge {
|
||||
if (AccessibilityServiceUtils.isAccessibilityServiceEnabled(App.getApp(), AccessibilityWatchDogService.class)) {
|
||||
errorMessage = App.getApp().getString(R.string.text_auto_operate_service_enabled_but_not_running);
|
||||
} else {
|
||||
if (Pref.def().getBoolean(App.getApp().getString(R.string.key_enable_accessibility_service_by_root), false)) {
|
||||
if (!AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(AccessibilityWatchDogService.class, 3000)) {
|
||||
if (Pref.enableAccessibilityServiceByRoot()) {
|
||||
if (!AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(2000)) {
|
||||
errorMessage = App.getApp().getString(R.string.text_enable_accessibility_service_by_root_timeout);
|
||||
}
|
||||
} else {
|
||||
|
||||
@@ -18,7 +18,7 @@ import android.view.View;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floating_window.content.MainMenuNavigatorContent;
|
||||
import com.stardust.scriptdroid.external.floating_window.content.RecordNavigatorContent;
|
||||
import com.stardust.scriptdroid.external.floating_window.content.ScritpListNavigatorContent;
|
||||
import com.stardust.scriptdroid.external.floating_window.content.ScriptListNavigatorContent;
|
||||
import com.stardust.theme.ThemeColorManagerCompat;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -52,7 +52,7 @@ public class HoverMenuAdapter implements io.mattcarroll.hover.HoverMenuAdapter {
|
||||
|
||||
mData.put(HoverMenuAdapter.ID_MAIN, new MainMenuNavigatorContent(context));
|
||||
mData.put(HoverMenuAdapter.ID_RECORD, new RecordNavigatorContent(context));
|
||||
mData.put(HoverMenuAdapter.ID_SCRIPT_LIST, new ScritpListNavigatorContent(context));
|
||||
mData.put(HoverMenuAdapter.ID_SCRIPT_LIST, new ScriptListNavigatorContent(context));
|
||||
|
||||
mTabIds = new ArrayList<>();
|
||||
for (String tabId : mData.keySet()) {
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.content;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.stardust.autojs.script.FileScriptSource;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
|
||||
import com.stardust.scriptdroid.scripts.ScriptFile;
|
||||
import com.stardust.scriptdroid.scripts.StorageScriptProvider;
|
||||
import com.stardust.scriptdroid.ui.edit.EditActivity;
|
||||
import com.stardust.scriptdroid.ui.main.script_list.ScriptAndFolderListRecyclerView;
|
||||
import com.stardust.scriptdroid.ui.main.script_list.ScriptListRecyclerView;
|
||||
import com.stardust.scriptdroid.ui.main.script_list.ScriptListWithProgressBarView;
|
||||
import com.stardust.util.MessageEvent;
|
||||
import com.stardust.widget.ViewHolderSupplier;
|
||||
|
||||
import io.mattcarroll.hover.Navigator;
|
||||
import io.mattcarroll.hover.NavigatorContent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class ScriptListNavigatorContent implements NavigatorContent {
|
||||
|
||||
private ViewHolderSupplier<ScriptAndFolderListRecyclerView.ViewHolder> mViewHolderSupplier = new ViewHolderSupplier<ScriptAndFolderListRecyclerView.ViewHolder>() {
|
||||
@Override
|
||||
public ScriptAndFolderListRecyclerView.ViewHolder createViewHolder(ViewGroup parent, int viewType) {
|
||||
switch (viewType) {
|
||||
case ScriptAndFolderListRecyclerView.VIEW_TYPE_FILE:
|
||||
return new FileViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.floating_script_list_recycler_view_file, parent, false));
|
||||
case ScriptAndFolderListRecyclerView.VIEW_TYPE_DIRECTORY:
|
||||
return new DirectoryViewHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.floating_script_list_recycler_view_directory, parent, false));
|
||||
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
private ScriptAndFolderListRecyclerView mFloatingScriptFileListView;
|
||||
private ScriptListWithProgressBarView mScriptListWithProgressBarView;
|
||||
|
||||
public ScriptListNavigatorContent(Context context) {
|
||||
mScriptListWithProgressBarView = new ScriptListWithProgressBarView(new ContextThemeWrapper(context, R.style.AppTheme));
|
||||
mFloatingScriptFileListView = mScriptListWithProgressBarView.getScriptAndFolderListRecyclerView();
|
||||
mFloatingScriptFileListView.setViewHolderSupplier(mViewHolderSupplier);
|
||||
mFloatingScriptFileListView.setStorageScriptProvider(StorageScriptProvider.getDefault());
|
||||
mFloatingScriptFileListView.setOnItemClickListener(new ScriptAndFolderListRecyclerView.OnScriptFileClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(ScriptFile file, int position) {
|
||||
AutoJs.getInstance().getScriptEngineService().execute(new FileScriptSource(file));
|
||||
HoverMenuService.postEvent(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView() {
|
||||
return mScriptListWithProgressBarView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(@NonNull Navigator navigator) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden() {
|
||||
|
||||
}
|
||||
|
||||
private class DirectoryViewHolder extends ScriptAndFolderListRecyclerView.ViewHolder {
|
||||
|
||||
DirectoryViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
itemView.setOnClickListener(mFloatingScriptFileListView.getOnItemClickListenerProxy());
|
||||
itemView.setOnLongClickListener(mFloatingScriptFileListView.getOnItemLongClickListenerProxy());
|
||||
}
|
||||
}
|
||||
|
||||
private class FileViewHolder extends DirectoryViewHolder {
|
||||
|
||||
FileViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
itemView.findViewById(R.id.edit).setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = mFloatingScriptFileListView.getChildViewHolder((View) v.getParent()).getAdapterPosition();
|
||||
ScriptFile file = mFloatingScriptFileListView.getAdapter().getScriptFileAt(position);
|
||||
EditActivity.editFile(v.getContext(), file);
|
||||
}
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
package com.stardust.scriptdroid.external.floating_window.content;
|
||||
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
|
||||
import com.stardust.scriptdroid.scripts.ScriptFileList;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.external.floating_window.view.FloatingScriptFileListView;
|
||||
|
||||
import io.mattcarroll.hover.Navigator;
|
||||
import io.mattcarroll.hover.NavigatorContent;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/3/12.
|
||||
*/
|
||||
|
||||
public class ScritpListNavigatorContent implements NavigatorContent {
|
||||
|
||||
private FloatingScriptFileListView mFloatingScriptFileListView;
|
||||
|
||||
public ScritpListNavigatorContent(Context context) {
|
||||
mFloatingScriptFileListView = new FloatingScriptFileListView(new ContextThemeWrapper(context, R.style.AppTheme));
|
||||
mFloatingScriptFileListView.setScriptFileList(ScriptFileList.getImpl());
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public View getView() {
|
||||
return mFloatingScriptFileListView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onShown(@NonNull Navigator navigator) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onHidden() {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@ package com.stardust.scriptdroid.external.floating_window.view;
|
||||
import android.content.Context;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.support.v7.widget.DividerItemDecoration;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -173,7 +172,7 @@ public class FloatingScriptFileListView extends RecyclerView {
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
View itemView = LayoutInflater.from(getContext()).inflate(R.layout.floating_script_list_recycler_view_item, parent, false);
|
||||
View itemView = LayoutInflater.from(getContext()).inflate(R.layout.floating_script_list_recycler_view_file, parent, false);
|
||||
return new ViewHolder(itemView);
|
||||
}
|
||||
|
||||
@@ -199,7 +198,7 @@ public class FloatingScriptFileListView extends RecyclerView {
|
||||
name = (TextView) itemView.findViewById(R.id.name);
|
||||
path = (TextView) itemView.findViewById(R.id.path);
|
||||
ViewUtil.$(itemView, R.id.edit).setOnClickListener(mOnEditIconClickListener);
|
||||
ViewUtil.$(itemView, R.id.more).setOnClickListener(mOnMoreIconClickListener);
|
||||
//ViewUtil.$(itemView, R.id.more).setOnClickListener(mOnMoreIconClickListener);
|
||||
itemView.setOnClickListener(mOnItemClickListener);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -46,7 +46,7 @@ public class TaskPrefEditActivity extends AbstractAppCompatPluginActivity {
|
||||
scriptList.setCurrentDirectory(StorageScriptProvider.DEFAULT_DIRECTORY);
|
||||
scriptList.setOnItemClickListener(new ScriptAndFolderListRecyclerView.OnScriptFileClickListener() {
|
||||
@Override
|
||||
public void onClick(ScriptFile file) {
|
||||
public void onClick(ScriptFile file, int position) {
|
||||
mSelectedScriptFilePath = file.getPath();
|
||||
finish();
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@ public class NodeInfo {
|
||||
}
|
||||
|
||||
private String simplifyId(String idResourceName) {
|
||||
if(idResourceName == null)
|
||||
if (idResourceName == null)
|
||||
return null;
|
||||
int i = idResourceName.indexOf('/');
|
||||
return idResourceName.substring(i + 1);
|
||||
@@ -75,13 +75,15 @@ public class NodeInfo {
|
||||
}
|
||||
|
||||
public static NodeInfo capture(@NonNull AccessibilityNodeInfo root) {
|
||||
AccessibilityNodeInfoAllocator allocator = new AccessibilityNodeInfoAllocator();
|
||||
NodeInfo nodeInfo = new NodeInfo(root);
|
||||
for (int i = 0; i < root.getChildCount(); i++) {
|
||||
AccessibilityNodeInfo child = AccessibilityNodeInfoAllocator.getGlobal().getChild(root, i);
|
||||
AccessibilityNodeInfo child = allocator.getChild(root, i);
|
||||
if (child != null) {
|
||||
nodeInfo.children.add(capture(child));
|
||||
}
|
||||
}
|
||||
allocator.recycleAll();
|
||||
return nodeInfo;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import android.view.accessibility.AccessibilityNodeInfo;
|
||||
import com.stardust.automator.simple_action.FilterAction;
|
||||
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
|
||||
import com.stardust.util.SparseArrayEntries;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoAllocator;
|
||||
import com.stardust.view.accessibility.AccessibilityNodeInfoHelper;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
@@ -121,11 +122,13 @@ public class AccessibilityActionConverter {
|
||||
AccessibilityNodeInfo source = event.getSource();
|
||||
if (source == null)
|
||||
return;
|
||||
List<AccessibilityNodeInfo> editableList = FilterAction.EditableFilter.findEditable(service.getRootInActiveWindow());
|
||||
AccessibilityNodeInfoAllocator allocator = new AccessibilityNodeInfoAllocator();
|
||||
List<AccessibilityNodeInfo> editableList = FilterAction.EditableFilter.findEditable(allocator, service.getRootInActiveWindow());
|
||||
int i = findInEditableList(editableList, source);
|
||||
recycle(editableList);
|
||||
sb.append("while(!input(").append(i).append(", \"").append(source.getText()).append("\"));");
|
||||
source.recycle();
|
||||
allocator.recycleAll();
|
||||
}
|
||||
|
||||
private void recycle(List<AccessibilityNodeInfo> list) {
|
||||
|
||||
@@ -18,8 +18,8 @@ public class TouchRecorder extends InputEventToJsRecorder {
|
||||
}
|
||||
|
||||
private void setUpTriggers() {
|
||||
setStartTriggerKey(Pref.def().getString(App.getResString(R.string.key_start_record_trigger), null));
|
||||
setStopTriggerKey(Pref.def().getString(App.getResString(R.string.key_stop_record_trigger), null));
|
||||
setStartTriggerKey(Pref.getStartRecordTrigger());
|
||||
setStopTriggerKey(Pref.getStopRecordTrigger());
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package com.stardust.scriptdroid.scripts;
|
||||
|
||||
import android.os.Environment;
|
||||
|
||||
import com.android.dex.util.FileUtils;
|
||||
import com.stardust.pio.PFile;
|
||||
|
||||
import java.io.File;
|
||||
@@ -24,7 +25,7 @@ public class ScriptFile extends File {
|
||||
}
|
||||
|
||||
private void init() {
|
||||
mSimplifiedName = PFile.getNameWithoutExtension(getPath());
|
||||
mSimplifiedName = PFile.getNameWithoutExtension(getName());
|
||||
mSimplifyPath = getPath();
|
||||
if (mSimplifyPath.startsWith(Environment.getExternalStorageDirectory().getPath())) {
|
||||
mSimplifyPath = mSimplifyPath.substring(Environment.getExternalStorageDirectory().getPath().length());
|
||||
@@ -37,7 +38,14 @@ public class ScriptFile extends File {
|
||||
}
|
||||
|
||||
public boolean renameTo(String newName) {
|
||||
return renameTo(new File(getParent(), newName));
|
||||
if (isDirectory())
|
||||
return renameTo(new File(getParent(), newName));
|
||||
else
|
||||
return renameTo(new File(getParent(), newName + getExtension()));
|
||||
}
|
||||
|
||||
private String getExtension() {
|
||||
return PFile.getExtension(getName());
|
||||
}
|
||||
|
||||
public String getSimplifiedPath() {
|
||||
@@ -91,4 +99,7 @@ public class ScriptFile extends File {
|
||||
return mSimplifiedName;
|
||||
}
|
||||
|
||||
public boolean moveTo(ScriptFile to) {
|
||||
return renameTo(new File(to, getName()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,12 +4,16 @@ import android.accessibilityservice.AccessibilityService;
|
||||
import android.os.Build;
|
||||
import android.util.Log;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.accessibility.AccessibilityNodeInfo;
|
||||
|
||||
import com.stardust.autojs.runtime.JavascriptInterface;
|
||||
import com.stardust.view.accessibility.AccessibilityDelegate;
|
||||
import com.stardust.scriptdroid.App;
|
||||
import com.stardust.scriptdroid.tool.AccessibilityServiceTool;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.Map;
|
||||
import java.util.SortedMap;
|
||||
@@ -26,7 +30,8 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
private static final String TAG = "AccessibilityWatchDog";
|
||||
|
||||
private static final SortedMap<Integer, AccessibilityDelegate> mDelegates = new TreeMap<>();
|
||||
private static WeakReference<AccessibilityWatchDogService> instance;
|
||||
private static final Object LOCK = new Object();
|
||||
private static AccessibilityWatchDogService instance;
|
||||
private Executor mExecutor = Executors.newSingleThreadExecutor();
|
||||
|
||||
public static void addDelegate(int uniquePriority, AccessibilityDelegate delegate) {
|
||||
@@ -38,9 +43,7 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
}
|
||||
|
||||
public static AccessibilityWatchDogService getInstance() {
|
||||
if (instance == null)
|
||||
return null;
|
||||
return instance.get();
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -58,24 +61,52 @@ public class AccessibilityWatchDogService extends AccessibilityService {
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public AccessibilityNodeInfo getRootInActiveWindow() {
|
||||
try {
|
||||
return super.getRootInActiveWindow();
|
||||
} catch (IllegalStateException e) {
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInterrupt() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
instance = null;
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onServiceConnected() {
|
||||
super.onServiceConnected();
|
||||
// FIXME: 2017/2/12 有时在无障碍中开启服务后这里不会调用服务也不会运行,安卓的BUG???
|
||||
Log.v(TAG, "onServiceConnected");
|
||||
instance = new WeakReference<>(this);
|
||||
instance = this;
|
||||
super.onServiceConnected();
|
||||
synchronized (LOCK) {
|
||||
LOCK.notifyAll();
|
||||
}
|
||||
// FIXME: 2017/2/12 有时在无障碍中开启服务后这里不会调用服务也不会运行,安卓的BUG???
|
||||
}
|
||||
|
||||
public static void disable() {
|
||||
if (instance != null && instance.get() != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
instance.get().disableSelf();
|
||||
if (instance != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||
instance.disableSelf();
|
||||
} else {
|
||||
AccessibilityServiceTool.goToAccessibilitySetting();
|
||||
}
|
||||
}
|
||||
|
||||
public static void waitForEnabled(long timeOut) {
|
||||
synchronized (LOCK) {
|
||||
try {
|
||||
LOCK.wait(timeOut);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package com.stardust.scriptdroid.tool;
|
||||
|
||||
import android.accessibilityservice.AccessibilityService;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
@@ -11,6 +14,8 @@ import com.stardust.scriptdroid.R;
|
||||
import com.stardust.util.Shell;
|
||||
import com.stardust.view.accessibility.AccessibilityServiceUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
import static com.stardust.view.accessibility.AccessibilityServiceUtils.isAccessibilityServiceEnabled;
|
||||
|
||||
/**
|
||||
@@ -20,8 +25,8 @@ import static com.stardust.view.accessibility.AccessibilityServiceUtils.isAccess
|
||||
public class AccessibilityServiceTool {
|
||||
|
||||
public static void enableAccessibilityService() {
|
||||
if (Pref.def().getBoolean(App.getApp().getString(R.string.key_enable_accessibility_service_by_root), false)) {
|
||||
if (!enableAccessibilityServiceByRootAndWaitFor(AccessibilityWatchDogService.class, 3000)) {
|
||||
if (Pref.enableAccessibilityServiceByRoot()) {
|
||||
if (!enableAccessibilityServiceByRoot(AccessibilityWatchDogService.class)) {
|
||||
goToAccessibilitySetting();
|
||||
}
|
||||
} else {
|
||||
@@ -41,28 +46,32 @@ public class AccessibilityServiceTool {
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean enableAccessibilityServiceByRootAndWaitFor(Class<AccessibilityWatchDogService> accessibilityService, int timeout) {
|
||||
Shell.execCommand("settings put secure enabled_accessibility_services %accessibility:"
|
||||
+ App.getApp().getPackageName() + "/" + accessibilityService.getName(), true);
|
||||
long millis = System.currentTimeMillis();
|
||||
while (true) {
|
||||
if (isAccessibilityServiceEnabled(App.getApp(), accessibilityService))
|
||||
return true;
|
||||
try {
|
||||
Thread.sleep(100);
|
||||
} catch (InterruptedException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (System.currentTimeMillis() - millis >= timeout) {
|
||||
return false;
|
||||
}
|
||||
private static final String cmd = "enabled=$(settings get secure enabled_accessibility_services)\n" +
|
||||
"pkg=%s\n" +
|
||||
"if [[ $enabled == *$pkg* ]]\n" +
|
||||
"then\n" +
|
||||
"echo already_enabled\n" +
|
||||
"else\n" +
|
||||
"enabled=$pkg:$enabled\n" +
|
||||
"settings put secure enabled_accessibility_services $enabled\n" +
|
||||
"fi";
|
||||
|
||||
public static boolean enableAccessibilityServiceByRoot(Class<? extends AccessibilityService> accessibilityService) {
|
||||
String serviceName = App.getApp().getPackageName() + "/" + accessibilityService.getName();
|
||||
return TextUtils.isEmpty(Shell.execCommand(String.format(Locale.getDefault(), cmd, serviceName), true).error);
|
||||
}
|
||||
|
||||
public static boolean enableAccessibilityServiceByRootAndWaitFor(long timeOut) {
|
||||
if (enableAccessibilityServiceByRoot(AccessibilityWatchDogService.class)) {
|
||||
AccessibilityWatchDogService.waitForEnabled(timeOut);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
public static void enableAccessibilityServiceByRootIfNeeded() {
|
||||
if (AccessibilityWatchDogService.getInstance() == null)
|
||||
if (Pref.def().getBoolean(App.getApp().getString(R.string.key_enable_accessibility_service_by_root), false)) {
|
||||
AccessibilityServiceTool.enableAccessibilityServiceByRootAndWaitFor(AccessibilityWatchDogService.class, 3000);
|
||||
if (Pref.enableAccessibilityServiceByRoot()) {
|
||||
AccessibilityServiceTool.enableAccessibilityServiceByRoot(AccessibilityWatchDogService.class);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,150 @@
|
||||
package com.stardust.scriptdroid.tool;
|
||||
|
||||
import android.content.Context;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import com.android.volley.DefaultRetryPolicy;
|
||||
import com.android.volley.Request;
|
||||
import com.android.volley.RequestQueue;
|
||||
import com.android.volley.Response;
|
||||
import com.android.volley.VolleyError;
|
||||
import com.android.volley.toolbox.StringRequest;
|
||||
import com.android.volley.toolbox.Volley;
|
||||
import com.google.gson.Gson;
|
||||
import com.google.gson.reflect.TypeToken;
|
||||
import com.stardust.pio.UncheckedIOException;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/9.
|
||||
*/
|
||||
|
||||
public class UpdateChecker implements Response.Listener<String>, Response.ErrorListener {
|
||||
|
||||
private static final String LOG_TAG = UpdateChecker.class.getName();
|
||||
private RequestQueue mRequestQueue;
|
||||
private static final String UPDATE_URL = "https://raw.githubusercontent.com/hyb1996/NoRootScriptDroid/master/version.json";
|
||||
|
||||
|
||||
public interface Callback {
|
||||
|
||||
void onSuccess(CheckResult result);
|
||||
|
||||
void onError(Exception exception);
|
||||
|
||||
}
|
||||
|
||||
private Callback mCallback;
|
||||
private final int mTimeOut = 3000;
|
||||
|
||||
public UpdateChecker(Context context, Callback callback) {
|
||||
mCallback = callback;
|
||||
mRequestQueue = Volley.newRequestQueue(context);
|
||||
}
|
||||
|
||||
private CheckResult parse(String json) {
|
||||
Gson gson = new Gson();
|
||||
Type type = new TypeToken<CheckResult>() {
|
||||
}.getType();
|
||||
CheckResult result = gson.fromJson(json, type);
|
||||
Log.i(LOG_TAG, result.toString());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public void check() {
|
||||
StringRequest request = new StringRequest(Request.Method.GET, UPDATE_URL, this, this);
|
||||
request.setRetryPolicy(new DefaultRetryPolicy(mTimeOut, DefaultRetryPolicy.DEFAULT_MAX_RETRIES, DefaultRetryPolicy.DEFAULT_BACKOFF_MULT));
|
||||
request.setTag("update-check");
|
||||
mRequestQueue.add(request);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onErrorResponse(VolleyError error) {
|
||||
error.printStackTrace();
|
||||
mCallback.onError(error);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResponse(String response) {
|
||||
try {
|
||||
CheckResult result = parse(response);
|
||||
if (result.isValid()) {
|
||||
mCallback.onSuccess(result);
|
||||
} else {
|
||||
mCallback.onError(new UpdateDataInvalidException());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
mCallback.onError(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
mRequestQueue.cancelAll("update-check");
|
||||
}
|
||||
|
||||
public static class CheckResult {
|
||||
|
||||
public int versionCode;
|
||||
public String releaseNotes;
|
||||
public String versionName;
|
||||
public List<Download> downloads;
|
||||
public List<OldVersion> oldVersions;
|
||||
public int deprecated;
|
||||
|
||||
public boolean isValid() {
|
||||
return downloads != null && !downloads.isEmpty() && versionCode > 0
|
||||
&& !TextUtils.isEmpty(versionName) && !TextUtils.isEmpty(releaseNotes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "CheckResult{" +
|
||||
"versionCode=" + versionCode +
|
||||
", releaseNotes='" + releaseNotes + '\'' +
|
||||
", versionName='" + versionName + '\'' +
|
||||
", downloads=" + downloads +
|
||||
", oldVersions=" + oldVersions +
|
||||
", deprecated=" + deprecated +
|
||||
'}';
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static class OldVersion {
|
||||
|
||||
public int versionCode;
|
||||
public String issues;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "OldVersion{" +
|
||||
"versionCode=" + versionCode +
|
||||
", issues='" + issues + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class Download {
|
||||
|
||||
public String name;
|
||||
public String url;
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "Download{" +
|
||||
"name='" + name + '\'' +
|
||||
", url='" + url + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
public static class UpdateDataInvalidException extends RuntimeException {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -84,8 +84,6 @@ public class EditActivity extends Editor920Activity {
|
||||
|
||||
public static final String EXTRA_CONTENT = "Still Love Eating 17.4.5";
|
||||
|
||||
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_MESSAGE = "EXTRA_EXCEPTION_MESSAGE";
|
||||
|
||||
@@ -173,14 +171,13 @@ public class EditActivity extends Editor920Activity {
|
||||
}
|
||||
|
||||
private void openDrawerIfFirstUse() {
|
||||
if (Pref.def().getBoolean(KEY_EDIT_ACTIVITY_FIRST_USE, true)) {
|
||||
if (Pref.isEditActivityFirstUsing()) {
|
||||
mDrawerLayout.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mDrawerLayout.openDrawer(GravityCompat.END);
|
||||
}
|
||||
}, 1000);
|
||||
Pref.def().edit().putBoolean(KEY_EDIT_ACTIVITY_FIRST_USE, false).apply();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -45,6 +45,7 @@ public class MyScriptListFragment extends Fragment {
|
||||
private ScriptFile mSelectedScriptFile;
|
||||
private MaterialDialog.InputCallback mFileNameInputCallback = new InputCallback(false);
|
||||
private MaterialDialog.InputCallback mDirectoryNameInputCallback = new InputCallback(true);
|
||||
private int mSelectedPosition;
|
||||
|
||||
@Override
|
||||
public void onCreate(@Nullable Bundle savedInstanceState) {
|
||||
@@ -82,14 +83,15 @@ public class MyScriptListFragment extends Fragment {
|
||||
});
|
||||
mScriptListRecyclerView.setOnItemClickListener(new ScriptAndFolderListRecyclerView.OnScriptFileClickListener() {
|
||||
@Override
|
||||
public void onClick(ScriptFile file) {
|
||||
public void onClick(ScriptFile file, int position) {
|
||||
EditActivity.editFile(getContext(), file);
|
||||
}
|
||||
});
|
||||
mScriptListRecyclerView.setOnItemLongClickListener(new ScriptAndFolderListRecyclerView.OnScriptFileLongClickListener() {
|
||||
@Override
|
||||
public void onLongClick(ScriptFile file) {
|
||||
public void onLongClick(ScriptFile file, int position) {
|
||||
mSelectedScriptFile = file;
|
||||
mSelectedPosition = position;
|
||||
if (file.isDirectory()) {
|
||||
mDirectoryOperationDialog.show();
|
||||
} else {
|
||||
@@ -226,6 +228,7 @@ public class MyScriptListFragment extends Fragment {
|
||||
@Override
|
||||
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
|
||||
mSelectedScriptFile.renameTo(input.toString());
|
||||
StorageScriptProvider.getDefault().notifyDirectoryChanged(mScriptListRecyclerView.getCurrentDirectory());
|
||||
onScriptFileOperated();
|
||||
}
|
||||
});
|
||||
|
||||
@@ -4,13 +4,13 @@ import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcelable;
|
||||
import android.support.annotation.Nullable;
|
||||
import android.support.v7.widget.LinearLayoutManager;
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
import android.workground.WrapContentLinearLayoutManager;
|
||||
@@ -20,8 +20,11 @@ import com.stardust.scriptdroid.autojs.AutoJs;
|
||||
import com.stardust.scriptdroid.scripts.ScriptFile;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.scripts.StorageScriptProvider;
|
||||
import com.stardust.widget.ViewHolderMutableAdapter;
|
||||
import com.stardust.widget.ViewHolderSupplier;
|
||||
import com.yqritc.recyclerviewflexibledivider.HorizontalDividerItemDecoration;
|
||||
|
||||
|
||||
import org.greenrobot.eventbus.Subscribe;
|
||||
|
||||
/**
|
||||
@@ -32,12 +35,12 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
|
||||
public interface OnScriptFileClickListener {
|
||||
|
||||
void onClick(ScriptFile file);
|
||||
void onClick(ScriptFile file, int position);
|
||||
}
|
||||
|
||||
public interface OnScriptFileLongClickListener {
|
||||
|
||||
void onLongClick(ScriptFile file);
|
||||
void onLongClick(ScriptFile file, int position);
|
||||
}
|
||||
|
||||
public interface FileProcessListener {
|
||||
@@ -47,6 +50,28 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
void onFileListed();
|
||||
}
|
||||
|
||||
public static final int VIEW_TYPE_DIRECTORY = 1;
|
||||
public static final int VIEW_TYPE_FILE = 2;
|
||||
|
||||
public static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
|
||||
TextView name;
|
||||
|
||||
public ViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
name = (TextView) itemView.findViewById(R.id.name);
|
||||
}
|
||||
|
||||
public void bind(ScriptFile file) {
|
||||
if (file.isDirectory()) {
|
||||
name.setText(file.getName());
|
||||
} else {
|
||||
name.setText(file.getSimplifiedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private OnScriptFileClickListener mOnItemClickListener;
|
||||
private OnScriptFileLongClickListener mOnItemLongClickListener;
|
||||
private final OnClickListener mOnItemClickListenerProxy = new OnClickListener() {
|
||||
@@ -57,11 +82,11 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
goBack();
|
||||
return;
|
||||
}
|
||||
ScriptFile file = mScriptFileList[getActualPosition(position)];
|
||||
ScriptFile file = mAdapter.getScriptFileAt(position);
|
||||
if (file.isDirectory()) {
|
||||
setCurrentDirectory(file, true);
|
||||
} else if (mOnItemClickListener != null) {
|
||||
mOnItemClickListener.onClick(file);
|
||||
mOnItemClickListener.onClick(file, position);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -70,7 +95,7 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
public boolean onLongClick(View v) {
|
||||
if (mOnItemLongClickListener != null) {
|
||||
int position = getChildViewHolder(v).getAdapterPosition();
|
||||
mOnItemLongClickListener.onLongClick(mScriptFileList[getActualPosition(position)]);
|
||||
mOnItemLongClickListener.onLongClick(mAdapter.getScriptFileAt(position), position);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
@@ -81,12 +106,23 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
int position = getChildViewHolder((View) v.getParent()).getAdapterPosition();
|
||||
ScriptFile file = mScriptFileList[getActualPosition(position)];
|
||||
ScriptFile file = mAdapter.getScriptFileAt(position);
|
||||
AutoJs.getInstance().getScriptEngineService().execute(new FileScriptSource(file));
|
||||
}
|
||||
};
|
||||
private final ViewHolderSupplier<ViewHolder> mDefaultViewHolderSupplier = new ViewHolderSupplier<ViewHolder>() {
|
||||
@Override
|
||||
public ViewHolder createViewHolder(ViewGroup parent, int viewType) {
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_FILE:
|
||||
return new FileViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.script_and_folder_list_recycler_view_file, parent, false));
|
||||
case VIEW_TYPE_DIRECTORY:
|
||||
return new DefaultViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.script_and_folder_list_recycler_view_directory, parent, false));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
private ScriptFile[] mScriptFileList = new ScriptFile[0];
|
||||
private ScriptFile mCurrentDirectory;
|
||||
private ScriptFile mRootDirectory;
|
||||
private Adapter mAdapter;
|
||||
@@ -119,12 +155,13 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mScriptFileList = mStorageScriptProvider.getDirectoryScriptFiles(directory);
|
||||
final ScriptFile[] scriptFiles = mStorageScriptProvider.getDirectoryScriptFiles(directory);
|
||||
post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mFileProcessListener.onFileListed();
|
||||
mAdapter.notifyDataSetChanged();
|
||||
mAdapter.setScripts(scriptFiles);
|
||||
if (mFileProcessListener != null)
|
||||
mFileProcessListener.onFileListed();
|
||||
}
|
||||
});
|
||||
}
|
||||
@@ -135,9 +172,8 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
setCurrentDirectory(directory, !directory.equals(mRootDirectory));
|
||||
}
|
||||
|
||||
private void setRootDirectory(ScriptFile folder) {
|
||||
mRootDirectory = folder;
|
||||
setCurrentDirectory(mRootDirectory, false);
|
||||
private void setRootDirectory(ScriptFile directory) {
|
||||
mRootDirectory = directory;
|
||||
}
|
||||
|
||||
public void setFileProcessListener(FileProcessListener fileProcessListener) {
|
||||
@@ -168,6 +204,18 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
mScriptFileOperationEnabled = scriptFileOperationEnabled;
|
||||
}
|
||||
|
||||
public void setViewHolderSupplier(ViewHolderSupplier<ViewHolder> supplier) {
|
||||
mAdapter.setViewHolderSupplier(supplier);
|
||||
}
|
||||
|
||||
public OnClickListener getOnItemClickListenerProxy() {
|
||||
return mOnItemClickListenerProxy;
|
||||
}
|
||||
|
||||
public OnLongClickListener getOnItemLongClickListenerProxy() {
|
||||
return mOnItemLongClickListenerProxy;
|
||||
}
|
||||
|
||||
private void goBack() {
|
||||
ScriptFile parent = mCurrentDirectory.getParentFile();
|
||||
setCurrentDirectory(parent, !parent.equals(mRootDirectory));
|
||||
@@ -181,10 +229,11 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
.marginResId(R.dimen.script_and_folder_list_divider_left_margin, R.dimen.script_and_folder_list_divider_right_margin)
|
||||
.showLastDivider()
|
||||
.build());
|
||||
mAdapter = new Adapter();
|
||||
mAdapter = new Adapter(mDefaultViewHolderSupplier);
|
||||
setAdapter(mAdapter);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected Parcelable onSaveInstanceState() {
|
||||
Bundle bundle = new Bundle();
|
||||
@@ -208,6 +257,7 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
super.onAttachedToWindow();
|
||||
if (mStorageScriptProvider != null)
|
||||
mStorageScriptProvider.registerDirectoryChangeListener(this);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -234,24 +284,28 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Adapter getAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
private void updateCurrentDirectory() {
|
||||
setCurrentDirectory(mCurrentDirectory, mCanGoBack);
|
||||
}
|
||||
|
||||
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
|
||||
private void ensureCurrentDirectory() {
|
||||
if (mCurrentDirectory == null && mRootDirectory != null) {
|
||||
setCurrentDirectory(mRootDirectory, false);
|
||||
}
|
||||
}
|
||||
|
||||
private final int VIEW_TYPE_FOLDER = 1;
|
||||
private final int VIEW_TYPE_FILE = 2;
|
||||
public class Adapter extends ViewHolderMutableAdapter<ViewHolder> {
|
||||
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
switch (viewType) {
|
||||
case VIEW_TYPE_FILE:
|
||||
return new FileViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.script_and_folder_list_recycler_view_file, parent, false));
|
||||
case VIEW_TYPE_FOLDER:
|
||||
return new ViewHolder(LayoutInflater.from(getContext()).inflate(R.layout.script_and_folder_list_recycler_view_directory, parent, false));
|
||||
}
|
||||
return null;
|
||||
private ScriptFile[] mScriptFileList = new ScriptFile[0];
|
||||
|
||||
public Adapter(ViewHolderSupplier<ViewHolder> viewHolderSupplier) {
|
||||
super(viewHolderSupplier);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -259,37 +313,41 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
if (mCanGoBack && position == 0) {
|
||||
holder.name.setText("..");
|
||||
} else
|
||||
holder.bind(mScriptFileList[getActualPosition(position)]);
|
||||
holder.bind(getScriptFileAt(position));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
ensureCurrentDirectory();
|
||||
return mScriptFileList.length + (mCanGoBack ? 1 : 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemViewType(int position) {
|
||||
if (mCanGoBack && position == 0) {
|
||||
return VIEW_TYPE_FOLDER;
|
||||
return VIEW_TYPE_DIRECTORY;
|
||||
}
|
||||
return mScriptFileList[getActualPosition(position)].isDirectory() ? VIEW_TYPE_FOLDER : VIEW_TYPE_FILE;
|
||||
return getScriptFileAt(position).isDirectory() ? VIEW_TYPE_DIRECTORY : VIEW_TYPE_FILE;
|
||||
}
|
||||
|
||||
public ScriptFile getScriptFileAt(int position) {
|
||||
return mScriptFileList[mCanGoBack ? position - 1 : position];
|
||||
}
|
||||
|
||||
void setScripts(ScriptFile[] scriptFiles) {
|
||||
mScriptFileList = scriptFiles;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
}
|
||||
|
||||
private int getActualPosition(int position) {
|
||||
return mCanGoBack ? position - 1 : position;
|
||||
}
|
||||
|
||||
|
||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||
private class DefaultViewHolder extends ViewHolder {
|
||||
|
||||
TextView name;
|
||||
|
||||
ViewHolder(View itemView) {
|
||||
DefaultViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
itemView.setOnClickListener(mOnItemClickListenerProxy);
|
||||
itemView.setOnLongClickListener(mOnItemLongClickListenerProxy);
|
||||
name = (TextView) itemView.findViewById(R.id.name);
|
||||
if (!mScriptFileOperationEnabled) {
|
||||
setMarginRight(name, 0);
|
||||
}
|
||||
@@ -301,16 +359,9 @@ public class ScriptAndFolderListRecyclerView extends RecyclerView {
|
||||
view.setLayoutParams(layoutParams);
|
||||
}
|
||||
|
||||
public void bind(ScriptFile file) {
|
||||
if (file.isDirectory()) {
|
||||
name.setText(file.getName());
|
||||
} else {
|
||||
name.setText(file.getSimplifiedName());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class FileViewHolder extends ViewHolder {
|
||||
private class FileViewHolder extends DefaultViewHolder {
|
||||
|
||||
FileViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
|
||||
@@ -52,7 +52,7 @@ public class ScriptFileChooserDialogBuilder extends MaterialDialog.Builder {
|
||||
if (mFileCallback != null) {
|
||||
mScriptListWithProgressBarView.setOnItemClickListener(new ScriptAndFolderListRecyclerView.OnScriptFileClickListener() {
|
||||
@Override
|
||||
public void onClick(ScriptFile file) {
|
||||
public void onClick(ScriptFile file, int position) {
|
||||
mFileCallback.onFileSelection(dialog, file);
|
||||
}
|
||||
});
|
||||
|
||||
@@ -128,7 +128,7 @@ public class TaskListRecyclerView extends ThemeColorRecyclerView implements Java
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(ViewHolder holder, int position) {
|
||||
holder.bind(mScriptEngines.get(position).getExecutedScript());
|
||||
holder.bind((ScriptSource) mScriptEngines.get(position).getTag("script"));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -46,10 +46,10 @@ public class TaskManagerFragment extends Fragment {
|
||||
@Override
|
||||
public void onSomethingChanged() {
|
||||
final boolean noRunningScript = mTaskListRecyclerView.getAdapter().getItemCount() == 0;
|
||||
mNoRunningScriptNotice.setVisibility(noRunningScript ? View.VISIBLE : View.GONE);
|
||||
mCloseAllView.postDelayed(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
mNoRunningScriptNotice.setVisibility(noRunningScript ? View.VISIBLE : View.GONE);
|
||||
mCloseAllView.setVisibility(noRunningScript ? View.GONE : View.VISIBLE);
|
||||
}
|
||||
}, 150);
|
||||
|
||||
@@ -11,9 +11,11 @@ import android.view.View;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.stardust.scriptdroid.Pref;
|
||||
import com.stardust.scriptdroid.tool.UpdateChecker;
|
||||
import com.stardust.scriptdroid.ui.BaseActivity;
|
||||
import com.stardust.scriptdroid.ui.error.IssueReporterActivity;
|
||||
import com.stardust.scriptdroid.ui.main.MainActivity;
|
||||
import com.stardust.scriptdroid.ui.update.UpdateCheckDialog;
|
||||
import com.stardust.util.IntentUtil;
|
||||
import com.stardust.util.MapEntries;
|
||||
import com.stardust.scriptdroid.R;
|
||||
@@ -115,6 +117,12 @@ public class SettingsActivity extends BaseActivity {
|
||||
EventBus.getDefault().post(new MessageEvent(MainActivity.MESSAGE_CLEAR_BACKGROUND_SETTINGS));
|
||||
}
|
||||
})
|
||||
.entry(getString(R.string.text_check_update), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
new UpdateCheckDialog(getActivity()).show();
|
||||
}
|
||||
})
|
||||
.entry(getString(R.string.text_issue_report), new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
package com.stardust.scriptdroid.ui.update;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.AsyncTask;
|
||||
import android.support.annotation.NonNull;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.afollestad.materialdialogs.DialogAction;
|
||||
import com.afollestad.materialdialogs.MaterialDialog;
|
||||
import com.stardust.scriptdroid.BuildConfig;
|
||||
import com.stardust.scriptdroid.R;
|
||||
import com.stardust.scriptdroid.tool.UpdateChecker;
|
||||
import com.stardust.util.IntentUtil;
|
||||
|
||||
import java.util.Timer;
|
||||
import java.util.TimerTask;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/9.
|
||||
*/
|
||||
|
||||
public class UpdateCheckDialog implements UpdateChecker.Callback {
|
||||
|
||||
private MaterialDialog mResultDialog;
|
||||
private MaterialDialog mProgressDialog;
|
||||
private Context mContext;
|
||||
private UpdateChecker mUpdateChecker;
|
||||
|
||||
|
||||
public UpdateCheckDialog(Context context) {
|
||||
mContext = context;
|
||||
mUpdateChecker = new UpdateChecker(context, this);
|
||||
}
|
||||
|
||||
public void show() {
|
||||
mProgressDialog = new MaterialDialog.Builder(mContext)
|
||||
.content(mContext.getString(R.string.text_checking_update))
|
||||
.progress(true, 0)
|
||||
.cancelable(false)
|
||||
.show();
|
||||
mUpdateChecker.check();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSuccess(UpdateChecker.CheckResult result) {
|
||||
mProgressDialog.dismiss();
|
||||
if (BuildConfig.VERSION_CODE >= result.versionCode) {
|
||||
Toast.makeText(mContext, R.string.text_is_latest_version, Toast.LENGTH_SHORT).show();
|
||||
return;
|
||||
}
|
||||
mResultDialog = buildDialog(result);
|
||||
mResultDialog.show();
|
||||
String updateSite = result.downloads.get(0).name;
|
||||
final String updateUrl = result.downloads.get(0).url;
|
||||
mResultDialog = new MaterialDialog.Builder(mContext)
|
||||
.title(mContext.getString(R.string.text_new_version) + " " + result.versionName)
|
||||
.content(result.releaseNotes)
|
||||
.positiveText(updateSite)
|
||||
.onPositive(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||
IntentUtil.browse(mContext, updateUrl);
|
||||
}
|
||||
})
|
||||
.show();
|
||||
}
|
||||
|
||||
private MaterialDialog buildDialog(final UpdateChecker.CheckResult result) {
|
||||
String updateSite = result.downloads.get(0).name;
|
||||
final String updateUrl = result.downloads.get(0).url;
|
||||
MaterialDialog.Builder builder = new MaterialDialog.Builder(mContext)
|
||||
.title(mContext.getString(R.string.text_new_version) + " " + result.versionName)
|
||||
.content(result.releaseNotes)
|
||||
.positiveText(updateSite)
|
||||
.onPositive(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||
IntentUtil.browse(mContext, updateUrl);
|
||||
}
|
||||
});
|
||||
if (result.downloads.size() > 1) {
|
||||
builder.negativeText(result.downloads.get(1).name)
|
||||
.onNegative(new MaterialDialog.SingleButtonCallback() {
|
||||
@Override
|
||||
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
|
||||
IntentUtil.browse(mContext, result.downloads.get(1).url);
|
||||
}
|
||||
});
|
||||
}
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onError(Exception exception) {
|
||||
mProgressDialog.dismiss();
|
||||
Toast.makeText(mContext, R.string.text_check_update_error, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/8.
|
||||
*/
|
||||
|
||||
public abstract class BindableViewHolder<DataType> extends RecyclerView.ViewHolder{
|
||||
|
||||
|
||||
public BindableViewHolder(View itemView) {
|
||||
super(itemView);
|
||||
}
|
||||
|
||||
public abstract void bind(DataType data);
|
||||
}
|
||||
@@ -0,0 +1,39 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.support.v7.widget.helper.ItemTouchHelper;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/6.
|
||||
*/
|
||||
|
||||
public class ItemTouchHelperSimpleCallback extends ItemTouchHelper.SimpleCallback {
|
||||
|
||||
private boolean mLongPressDragEnabled, mItemViewSwipeEnabled;
|
||||
|
||||
public ItemTouchHelperSimpleCallback(int dragDirs, int swipeDirs) {
|
||||
super(dragDirs, swipeDirs);
|
||||
mItemViewSwipeEnabled = swipeDirs != 0;
|
||||
mLongPressDragEnabled = dragDirs != 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLongPressDragEnabled() {
|
||||
return mLongPressDragEnabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isItemViewSwipeEnabled() {
|
||||
return mItemViewSwipeEnabled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/8.
|
||||
*/
|
||||
|
||||
public abstract class ViewHolderMutableAdapter<VH extends RecyclerView.ViewHolder> extends RecyclerView.Adapter<VH> {
|
||||
|
||||
private ViewHolderSupplier<VH> mViewHolderSupplier;
|
||||
|
||||
public ViewHolderMutableAdapter(ViewHolderSupplier<VH> viewHolderSupplier) {
|
||||
mViewHolderSupplier = viewHolderSupplier;
|
||||
}
|
||||
|
||||
@Override
|
||||
public VH onCreateViewHolder(ViewGroup parent, int viewType) {
|
||||
return mViewHolderSupplier.createViewHolder(parent, viewType);
|
||||
}
|
||||
|
||||
public void setViewHolderSupplier(ViewHolderSupplier<VH> viewHolderSupplier) {
|
||||
mViewHolderSupplier = viewHolderSupplier;
|
||||
notifyDataSetChanged();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package com.stardust.widget;
|
||||
|
||||
import android.support.v7.widget.RecyclerView;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Created by Stardust on 2017/4/8.
|
||||
*/
|
||||
|
||||
public abstract class ViewHolderSupplier<VH extends RecyclerView.ViewHolder> {
|
||||
|
||||
public abstract VH createViewHolder(ViewGroup parent, int viewType);
|
||||
|
||||
}
|
||||
BIN
app/src/main/res/drawable/ic_folder_outline_white.png
Normal file
BIN
app/src/main/res/drawable/ic_folder_outline_white.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?android:selectableItemBackground">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:contentDescription="@string/_app_name"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_folder_yellow_100px"/>
|
||||
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="80dp"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/primary_text_dark"
|
||||
android:textSize="16sp"
|
||||
tools:text="示例脚本"/>
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -0,0 +1,57 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?android:selectableItemBackground"
|
||||
tools:background="@color/colorPrimary">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/icon"
|
||||
android:layout_width="40dp"
|
||||
android:layout_height="40dp"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:contentDescription="@string/_app_name"
|
||||
android:scaleType="fitCenter"
|
||||
android:src="@drawable/ic_node_js_black"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginLeft="8dp"
|
||||
android:layout_marginRight="54dp"
|
||||
android:layout_toRightOf="@id/icon"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/primary_text_dark"
|
||||
android:textSize="16sp"
|
||||
tools:text="正在运行的服务"/>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/edit"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="12dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="24dp"
|
||||
android:layout_height="24dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/_app_name"
|
||||
android:src="@drawable/ic_edit_white"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -1,78 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:foreground="?android:attr/selectableItemBackground"
|
||||
android:orientation="vertical"
|
||||
android:paddingBottom="12dp"
|
||||
android:paddingLeft="16dp"
|
||||
android:paddingTop="12dp"
|
||||
tools:background="@color/colorPrimary">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentLeft="true"
|
||||
android:layout_marginRight="80dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/name"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="@android:color/primary_text_dark"
|
||||
android:textSize="18sp"
|
||||
tools:text="正在运行的服务"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/path"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="1"
|
||||
android:textColor="#e4e4e4"
|
||||
android:textSize="14sp"
|
||||
tools:text="/storage/emulated/0/脚本/正在运行的服务.txt"/>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/edit"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:layout_marginRight="42dp"
|
||||
android:background="?attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/_app_name"
|
||||
android:src="@drawable/ic_edit_white"/>
|
||||
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
<FrameLayout
|
||||
android:id="@+id/more"
|
||||
android:layout_width="42dp"
|
||||
android:layout_height="42dp"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_centerVertical="true"
|
||||
android:background="?attr/selectableItemBackgroundBorderless">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="20dp"
|
||||
android:layout_height="20dp"
|
||||
android:layout_gravity="center"
|
||||
android:contentDescription="@string/_app_name"
|
||||
android:src="@drawable/more_three_dots_ios_7_white"/>
|
||||
</FrameLayout>
|
||||
|
||||
|
||||
</RelativeLayout>
|
||||
@@ -158,6 +158,9 @@
|
||||
<string name="text_please_choose_file_to_import">请选择要导入的脚本</string>
|
||||
<string name="text_refresh">刷新</string>
|
||||
<string name="notice_no_running_script"><![CDATA[没有正在运行的脚本 φ(>ω<*)]]></string>
|
||||
<string name="text_checking_update">正在检查更新</string>
|
||||
<string name="text_new_version">新版本</string>
|
||||
<string name="text_is_latest_version">已经是最新版本</string>
|
||||
<string-array name="record_control_keys">
|
||||
<item>None</item>
|
||||
<item>Volume Up</item>
|
||||
|
||||
@@ -194,6 +194,11 @@
|
||||
<string name="text_clear_pre_execute_script">清空预执行脚本</string>
|
||||
<string name="text_clear_file_selection">重置脚本文件选择</string>
|
||||
<string name="summary_pre_execute_script">将在脚本文件执行前执行</string>
|
||||
<string name="text_checking_update">正在检查更新</string>
|
||||
<string name="text_new_version">新版本</string>
|
||||
<string name="text_check_update_error">检查更新失败Orz</string>
|
||||
<string name="text_check_update">检查更新</string>
|
||||
<string name="text_is_latest_version">已经是最新版本</string>
|
||||
|
||||
<string-array name="record_control_keys">
|
||||
<item>无</item>
|
||||
|
||||
@@ -67,13 +67,15 @@
|
||||
android:entries="@array/run_mode_keys"
|
||||
android:entryValues="@array/run_mode_values"
|
||||
android:key="@string/key_run_mode"
|
||||
android:title="@string/text_command_run_mode"
|
||||
android:summary="@string/summary_command_run_mode"
|
||||
android:title="@string/text_command_run_mode"
|
||||
/>
|
||||
</com.stardust.theme.preference.ThemeColorPreferenceCategory>
|
||||
|
||||
<com.stardust.theme.preference.ThemeColorPreferenceCategory android:title="@string/text_about">
|
||||
|
||||
<Preference android:title="@string/text_check_update"/>
|
||||
|
||||
<Preference android:title="@string/text_issue_report"/>
|
||||
|
||||
<Preference android:title="@string/text_join_qq_group"/>
|
||||
|
||||
Reference in New Issue
Block a user