fix: record isn't stopped when volume down

refactor: recorder
This commit is contained in:
hyb1996 2017-08-12 14:14:49 +08:00
parent 5ee99b5379
commit 4129f83cb1
11 changed files with 434 additions and 271 deletions

View File

@ -11,6 +11,7 @@ import com.squareup.leakcanary.LeakCanary;
import com.stardust.app.SimpleActivityLifecycleCallbacks;
import com.stardust.app.VolumeChangeObserver;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.autojs.record.GlobalRecorder;
import com.stardust.scriptdroid.statics.ScriptStatics;
import com.stardust.scriptdroid.tool.CrashHandler;
import com.stardust.scriptdroid.tool.JsBeautifierFactory;
@ -69,6 +70,7 @@ public class App extends MultiDexApplication {
AutoJs.initInstance(this);
JsBeautifierFactory.initJsBeautify(this, "js/jsbeautify.js");
initVolumeChangeObserver();
GlobalRecorder.initSingleton(this);
}
private void initVolumeChangeObserver() {

View File

@ -59,21 +59,6 @@ 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 hasRecordTrigger() {
String startTrigger = getStartRecordTrigger();
String stopTrigger = getStartRecordTrigger();
return startTrigger != null && !startTrigger.equals("NONE")
&& stopTrigger != null && !startTrigger.equals("NONE");
}
public static boolean enableAccessibilityServiceByRoot() {
return def().getBoolean(getString(R.string.key_enable_accessibility_service_by_root), false);
}
@ -135,4 +120,8 @@ public class Pref {
public static boolean isFirstShowingAd() {
return getDisposableBoolean(KEY_FIRST_SHOW_AD, true);
}
public static boolean isRecordWithRootEnabled() {
return def().getBoolean(getString(R.string.key_record_with_root), false);
}
}

View File

@ -1,28 +1,229 @@
package com.stardust.scriptdroid.autojs.record;
import android.content.Context;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.view.ContextThemeWrapper;
import android.view.KeyEvent;
import android.view.View;
import android.widget.Toast;
import com.afollestad.materialdialogs.DialogAction;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.app.DialogUtils;
import com.stardust.autojs.core.inputevent.InputEventCodes;
import com.stardust.autojs.core.inputevent.ShellKeyObserver;
import com.stardust.autojs.core.record.Recorder;
import com.stardust.autojs.core.record.inputevent.TouchRecorder;
import com.stardust.autojs.runtime.api.Shell;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import com.stardust.util.ClipboardUtil;
import com.stardust.view.accessibility.AccessibilityService;
import com.stardust.view.accessibility.OnKeyListener;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Created by Stardust on 2017/8/6.
*/
public class GlobalRecorder extends Recorder.AbstractRecorder {
public class GlobalRecorder implements Recorder.OnStateChangedListener {
private static GlobalRecorder sSingleton;
private Recorder mRecorder;
private CopyOnWriteArrayList<Recorder.OnStateChangedListener> mOnStateChangedListeners = new CopyOnWriteArrayList<>();
private TouchRecorder mTouchRecorder;
private Context mContext;
private boolean mDiscard = false;
private long mLastVolumeDownEventTime;
private ShellKeyObserver mShellKeyObserver;
@Override
protected void startImpl() {
public static GlobalRecorder getSingleton(Context context) {
if (sSingleton == null) {
sSingleton = new GlobalRecorder(context);
}
return sSingleton;
}
@Override
protected void stopImpl() {
public static void initSingleton(Context context) {
getSingleton(context);
}
public GlobalRecorder(Context context) {
mContext = new ContextThemeWrapper(context.getApplicationContext(), R.style.AppTheme);
mTouchRecorder = new TouchRecorder(context);
addKeyListeners();
}
private void addKeyListeners() {
AccessibilityService.getStickOnKeyObserver().addListener(new OnKeyListener() {
@Override
public void onKeyEvent(int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN &&
(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)) {
onVolumeDown();
}
}
});
mShellKeyObserver = new ShellKeyObserver();
mShellKeyObserver.setKeyListener(new ShellKeyObserver.KeyListener() {
@Override
public void onKeyDown(String keyName) {
if ("KEY_VOLUMEDOWN".equals(keyName)) {
onVolumeDown();
}
}
@Override
public void onKeyUp(String keyName) {
}
});
}
private void onVolumeDown() {
if (System.currentTimeMillis() - mLastVolumeDownEventTime < 300) {
return;
}
mLastVolumeDownEventTime = System.currentTimeMillis();
int state = getState();
if (state == Recorder.STATE_RECORDING || state == Recorder.STATE_PAUSED) {
stop();
} else {
start();
}
}
public void start() {
if (Pref.isRecordWithRootEnabled()) {
mTouchRecorder.reset();
mRecorder = mTouchRecorder;
} else {
mRecorder = AutoJs.getInstance().getAccessibilityActionRecorder();
}
mDiscard = false;
mRecorder.setOnStateChangedListener(this);
mRecorder.start();
}
public void pause() {
mRecorder.pause();
}
public void resume() {
mRecorder.resume();
}
public void stop() {
mRecorder.stop();
}
@Override
public String getCode() {
return null;
return mRecorder.getCode();
}
public int getState() {
if (mRecorder == null)
return Recorder.STATE_NOT_START;
return mRecorder.getState();
}
public void addOnStateChangedListener(Recorder.OnStateChangedListener listener) {
mOnStateChangedListeners.add(listener);
}
public boolean removeOnStateChangedListener(Recorder.OnStateChangedListener listener) {
return mOnStateChangedListeners.remove(listener);
}
@Override
public void onStart() {
App.getApp().getUiHandler().toast(R.string.text_start_record);
for (Recorder.OnStateChangedListener listener : mOnStateChangedListeners) {
listener.onStart();
}
}
@Override
public void onStop() {
if (!mDiscard) {
handleRecordedScript(getCode());
}
for (Recorder.OnStateChangedListener listener : mOnStateChangedListeners) {
listener.onStop();
}
}
@Override
public void onPause() {
for (Recorder.OnStateChangedListener listener : mOnStateChangedListeners) {
listener.onPause();
}
}
@Override
public void onResume() {
for (Recorder.OnStateChangedListener listener : mOnStateChangedListeners) {
listener.onResume();
}
}
public void discard() {
mDiscard = true;
stop();
}
private void handleRecordedScript(final String script) {
if (Looper.myLooper() == Looper.getMainLooper()) {
showRecordHandleDialog(script);
} else {
App.getApp().getUiHandler().post(new Runnable() {
@Override
public void run() {
showRecordHandleDialog(script);
}
});
}
}
private void showRecordHandleDialog(final String script) {
DialogUtils.showDialog(new ThemeColorMaterialDialogBuilder(mContext)
.title(R.string.text_recorded)
.items(getString(R.string.text_new_file), getString(R.string.text_copy_to_clip))
.itemsCallback(new MaterialDialog.ListCallback() {
@Override
public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) {
if (position == 0) {
new ScriptOperations(mContext, null)
.newScriptFileForScript(script);
} else {
ClipboardUtil.setClip(mContext, script);
Toast.makeText(mContext, R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
}
}
})
.negativeText(R.string.text_cancel)
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
}
})
.canceledOnTouchOutside(false)
.build());
}
private String getString(int res) {
return mContext.getString(res);
}
}

View File

@ -24,6 +24,7 @@ import com.stardust.scriptdroid.Pref;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.accessibility.AccessibilityEventHelper;
import com.stardust.scriptdroid.autojs.AutoJs;
import com.stardust.scriptdroid.autojs.record.GlobalRecorder;
import com.stardust.scriptdroid.external.floatingwindow.menu.HoverMenuService;
import com.stardust.scriptdroid.ui.common.ScriptOperations;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
@ -31,6 +32,8 @@ import com.stardust.util.ClipboardUtil;
import com.stardust.util.MessageEvent;
import com.stardust.view.accessibility.AccessibilityService;
import com.stardust.view.accessibility.OnKeyListener;
import com.stardust.widget.PrefSwitch;
import com.stardust.widget.ViewSwitcher;
import org.greenrobot.eventbus.Subscribe;
@ -45,61 +48,36 @@ import io.mattcarroll.hover.NavigatorContent;
* Created by Stardust on 2017/3/12.
*/
public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStateChangedListener, ShellKeyObserver.KeyListener {
public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStateChangedListener {
private View mView;
@BindView(R.id.sw_recorded_by_root)
SwitchCompat mRecordedByRootSwitch;
PrefSwitch mRecordedByRootSwitch;
@BindView(R.id.sw_record_toast)
SwitchCompat mRecordToastSwitch;
@BindView(R.id.img_start_or_pause)
ImageView mStartOrPauseRecordIcon;
@BindView(R.id.img_pause_or_resume)
ImageView mPauseOrResumeImage;
@BindView(R.id.text_start_or_pause)
TextView mStartOrPauseRecordText;
@BindView(R.id.text_pause_or_resume)
TextView mPauseOrResumeText;
@BindView(R.id.stop_record)
View mStopRecord;
@BindView(R.id.view_switcher)
ViewSwitcher mViewSwitcher;
@BindView(R.id.discard_record)
View mDiscardRecord;
private Recorder mRecorder;
private TouchRecorder mTouchRecorder;
private GlobalRecorder mRecorder;
private Context mContext;
private boolean mDiscard = false;
private ShellKeyObserver mKeyObserver;
private InputEventObserver mInputEventObserver = InputEventObserver.getGlobal();
private OnKeyListener mVolumeKeyListener = new OnKeyListener() {
@Override
public void onKeyEvent(int keyCode, KeyEvent event) {
if (event.getAction() == KeyEvent.ACTION_DOWN &&
(keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
&& Pref.isRecordVolumeControlEnable()) {
if (mRecorder == null) {
startRecord();
} else if (alreadyStartRecord()) {
stopRecord();
}
}
}
};
public RecordNavigatorContent(Context context) {
mContext = new ContextThemeWrapper(context, R.style.AppTheme);
mView = View.inflate(context, R.layout.floating_window_record, null);
ButterKnife.bind(this, mView);
HoverMenuService.getEventBus().register(this);
AccessibilityService.getStickOnKeyObserver().addListener(mVolumeKeyListener);
mTouchRecorder = TouchRecorder.getGlobal(context);
if (Pref.hasRecordTrigger()) {
mKeyObserver = new ShellKeyObserver();
mInputEventObserver.addListener(mKeyObserver);
mKeyObserver.setKeyListener(this);
}
mRecorder = GlobalRecorder.getSingleton(context);
mRecorder.addOnStateChangedListener(this);
setState(mRecorder.getState());
}
@NonNull
@ -128,57 +106,38 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
mRecordToastSwitch.toggle();
}
@OnClick(R.id.start_or_pause)
void startOrPauseRecord() {
if (mRecorder == null) {
startRecord();
} else if (mRecorder.getState() == Recorder.STATE_PAUSED) {
resumeRecord();
} else {
pauseRecord();
}
@OnClick(R.id.start_record)
void startRecord() {
mRecorder.start();
HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU));
}
@OnClick(R.id.discard_record)
void discardRecord() {
mDiscard = true;
stopRecord();
mRecorder.discard();
}
private void resumeRecord() {
mRecorder.resume();
setState(Recorder.STATE_RECORDING);
HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU));
}
private void pauseRecord() {
mRecorder.pause();
setState(Recorder.STATE_PAUSED);
}
private void startRecord() {
mDiscard = false;
if (mRecordedByRootSwitch.isChecked()) {
mTouchRecorder.reset();
mRecorder = mTouchRecorder;
@OnClick(R.id.pause_or_resume_record)
void pauseOrResumeRecord() {
if (mRecorder.getState() == Recorder.STATE_PAUSED) {
mRecorder.resume();
} else {
mRecorder = AutoJs.getInstance().getAccessibilityActionRecorder();
mRecorder.pause();
}
mRecorder.setOnStateChangedListener(this);
mRecorder.start();
setState(Recorder.STATE_RECORDING);
HoverMenuService.postIntent(new Intent(HoverMenuService.ACTION_COLLAPSE_MENU));
}
private void setState(int state) {
mStopRecord.setVisibility(state == Recorder.STATE_STOPPED ? View.GONE : View.VISIBLE);
mDiscardRecord.setVisibility(state == Recorder.STATE_STOPPED ? View.GONE : View.VISIBLE);
mStartOrPauseRecordIcon.setImageResource(state == Recorder.STATE_RECORDING ? R.drawable.ic_pause_white_24dp : R.drawable.ic_play_arrow_white_48dp);
mStartOrPauseRecordText.setText(
state == Recorder.STATE_RECORDING ? R.string.text_pause_record :
state == Recorder.STATE_PAUSED ? R.string.text_resume_record :
R.string.text_start_record);
if (state == Recorder.STATE_NOT_START || state == Recorder.STATE_STOPPED) {
mViewSwitcher.showFirst();
} else {
mViewSwitcher.showSecond();
}
mPauseOrResumeImage.setImageResource(state == Recorder.STATE_RECORDING ? R.drawable.ic_pause_white_24dp :
R.drawable.ic_play_arrow_white_48dp);
mPauseOrResumeText.setText(
state == Recorder.STATE_RECORDING ? R.string.text_pause_record : R.string.text_resume_record);
}
@OnClick(R.id.stop_record)
@ -192,8 +151,8 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
@Subscribe
public void onMessageEvent(MessageEvent event) {
if (event.message.equals(HoverMenuService.ACTION_MENU_EXPANDING)) {
if (mRecorder != null && mRecorder.getState() == Recorder.STATE_RECORDING)
pauseRecord();
if (mRecorder.getState() == Recorder.STATE_RECORDING)
mRecorder.pause();
} else if (event.message.equals(HoverMenuService.ACTION_MENU_EXIT)) {
onMenuExit();
}
@ -201,9 +160,7 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
public void onMenuExit() {
HoverMenuService.getEventBus().unregister(this);
AccessibilityService.getStickOnKeyObserver().addListener(mVolumeKeyListener);
mInputEventObserver.recycle();
mInputEventObserver.removeListener(mKeyObserver);
mRecorder.removeOnStateChangedListener(this);
}
@Subscribe
@ -215,80 +172,21 @@ public class RecordNavigatorContent implements NavigatorContent, Recorder.OnStat
@Override
public void onStart() {
App.getApp().getUiHandler().toast(R.string.text_start_record);
setState(Recorder.STATE_RECORDING);
}
@Override
public void onStop() {
if (!mDiscard) {
if (mRecorder instanceof TouchRecorder) {
new ScriptOperations(mContext, null)
.importFile(mRecorder.getCode())
.subscribe();
} else {
handleRecordedScript(mRecorder.getCode());
}
}
mRecorder = null;
}
private void handleRecordedScript(final String script) {
DialogUtils.showDialog(new ThemeColorMaterialDialogBuilder(mContext)
.title(R.string.text_recorded)
.items(getString(R.string.text_new_file), getString(R.string.text_copy_to_clip))
.itemsCallback(new MaterialDialog.ListCallback() {
@Override
public void onSelection(MaterialDialog dialog, View itemView, int position, CharSequence text) {
if (position == 0) {
new ScriptOperations(mContext, null)
.newScriptFileForScript(script);
} else {
ClipboardUtil.setClip(mContext, script);
Toast.makeText(mContext, R.string.text_already_copy_to_clip, Toast.LENGTH_SHORT).show();
}
}
})
.negativeText(R.string.text_cancel)
.onNegative(new MaterialDialog.SingleButtonCallback() {
@Override
public void onClick(@NonNull MaterialDialog dialog, @NonNull DialogAction which) {
dialog.dismiss();
}
})
.canceledOnTouchOutside(false)
.build());
}
private String getString(int res) {
return mContext.getString(res);
setState(Recorder.STATE_STOPPED);
}
@Override
public void onPause() {
setState(Recorder.STATE_PAUSED);
}
@Override
public void onResume() {
setState(Recorder.STATE_RECORDING);
}
@Override
public void onKeyDown(String keyName) {
if (keyName.equals(Pref.getStopRecordTrigger())) {
if (alreadyStartRecord())
stopRecord();
} else if (keyName.equals(Pref.getStartRecordTrigger())) {
if (mRecorder == null)
startRecord();
}
}
private boolean alreadyStartRecord() {
return mRecorder != null && mRecorder.getState() == Recorder.STATE_RECORDING && mRecorder.getState() == Recorder.STATE_PAUSED;
}
@Override
public void onKeyUp(String keyName) {
}
}
}

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size
android:width="100dp"
android:height="0.77dp"/>
<solid android:color="#efefef"/>
</shape>

View File

@ -11,7 +11,9 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
android:divider="@drawable/floating_menu_divider"
android:orientation="vertical"
android:showDividers="middle">
<TextView
android:layout_width="match_parent"
@ -21,10 +23,6 @@
android:textColor="@android:color/primary_text_dark"
android:textSize="20sp"/>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#c4c4c4"/>
<RelativeLayout
android:id="@+id/sw_root_container"
@ -49,17 +47,13 @@
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_toLeftOf="@id/sw_recorded_by_root"
android:gravity="center_vertical"
android:text="@string/text_record_with_root"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#c4c4c4"/>
<RelativeLayout
android:id="@+id/sw_record_toast_container"
android:layout_width="match_parent"
@ -87,104 +81,18 @@
</RelativeLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#c4c4c4"/>
<LinearLayout
android:id="@+id/start_or_pause"
<com.stardust.widget.ViewSwitcher
android:id="@+id/view_switcher"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingTop="16dp">
android:measureAllChildren="false">
<ImageView
android:id="@+id/img_start_or_pause"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_play_arrow_white_48dp"/>
<include layout="@layout/floating_window_record_start"/>
<TextView
android:id="@+id/text_start_or_pause"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_start_record"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
<include layout="@layout/floating_window_record_pause"/>
</LinearLayout>
</com.stardust.widget.ViewSwitcher>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#c4c4c4"/>
<LinearLayout
android:id="@+id/stop_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingTop="16dp"
android:visibility="gone">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_stop_white_36pt"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_stop_record"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#c4c4c4"/>
<LinearLayout
android:id="@+id/discard_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingTop="16dp"
android:visibility="gone">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_close_white_24dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_discard_record"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#c4c4c4"/>
</LinearLayout>

View File

@ -0,0 +1,88 @@
<?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:divider="@drawable/floating_menu_divider"
android:orientation="vertical"
android:showDividers="middle|end">
<LinearLayout
android:id="@+id/pause_or_resume_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingTop="16dp">
<ImageView
android:id="@+id/img_pause_or_resume"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_pause_white_24dp"/>
<TextView
android:id="@+id/text_pause_or_resume"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_pause_record"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/stop_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingTop="16dp">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_stop_white_36pt"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_stop_record"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
</LinearLayout>
<LinearLayout
android:id="@+id/discard_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingTop="16dp">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_close_white_24dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_discard_record"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>

View File

@ -0,0 +1,34 @@
<?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:divider="@drawable/floating_menu_divider"
android:orientation="vertical"
android:showDividers="middle|end">
<LinearLayout
android:id="@+id/start_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?android:attr/selectableItemBackground"
android:gravity="center_vertical"
android:paddingBottom="16dp"
android:paddingLeft="8dp"
android:paddingTop="16dp">
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_marginRight="8dp"
android:src="@drawable/ic_play_arrow_white_48dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/text_start_record"
android:textColor="@android:color/primary_text_dark"
android:textSize="16sp"/>
</LinearLayout>
</LinearLayout>

View File

@ -4,6 +4,7 @@ import android.support.annotation.NonNull;
import static com.stardust.autojs.core.record.inputevent.InputEventRecorder.parseDeviceNumber;
/**
* Created by Stardust on 2017/7/20.
*/

View File

@ -38,7 +38,7 @@ public abstract class InputEventRecorder extends Recorder.AbstractRecorder imple
public abstract String getCode();
protected static int parseDeviceNumber(String device) {
public static int parseDeviceNumber(String device) {
Matcher matcher = LAST_INT_PATTERN.matcher(device);
if (matcher.find()) {
String someNumberStr = matcher.group(1);

View File

@ -0,0 +1,32 @@
package com.stardust.event;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* Created by Stardust on 2017/8/6.
*/
public class EventDispatcher<Listener> {
public interface Event<Listener> {
void notify(Listener l);
}
private CopyOnWriteArrayList<Listener> mListeners = new CopyOnWriteArrayList<>();
public void addListener(Listener l) {
mListeners.add(l);
}
public boolean removeListener(Listener l) {
return mListeners.remove(l);
}
public void dispatchEvent(Event<Listener> event) {
for (Listener listener : mListeners) {
event.notify(listener);
}
}
}