Add: floating window, layout inspector

This commit is contained in:
hyb1996
2017-03-12 23:10:58 +08:00
parent a211d208d0
commit e81b661974
164 changed files with 7045 additions and 1206 deletions

View File

@@ -0,0 +1,32 @@
package com.stardust.scriptdroid.external.floating_window;
import android.content.Intent;
import android.view.View;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.layout_inspector.view.LayoutInspectView;
import com.stardust.view.Floaty;
import com.stardust.view.ResizableFloaty;
/**
* Created by Stardust on 2017/3/10.
*/
public class FloatingWindowManger {
public static void showFloatingWindow() {
if (!HoverMenuService.isServiceRunning())
App.getApp().startService(new Intent(App.getApp(), HoverMenuService.class));
}
public static boolean isFloatingWindowShowing() {
return HoverMenuService.isServiceRunning();
}
public static void hideFloatingWindow() {
if (HoverMenuService.isServiceRunning())
HoverMenuService.stopService();
}
}

View File

@@ -0,0 +1,214 @@
package com.stardust.scriptdroid.external.floating_window;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PorterDuff;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.support.annotation.ColorInt;
import android.support.annotation.DrawableRes;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.TypedValue;
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.theme.ThemeColorManagerCompat;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import io.mattcarroll.hover.NavigatorContent;
/**
* Created by Stardust on 2017/3/11.
*/
public class HoverMenuAdapter implements io.mattcarroll.hover.HoverMenuAdapter {
public static final String ID_MAIN = "intro";
public static final String ID_RECORD = "record";
public static final String ID_SCRIPT_LIST = "script_list";
public static final String MENU_ID = "menu";
public static final String PLACEHOLDER_ID = "placeholder";
private final Context mContext;
private final List<String> mTabIds;
private final Map<String, NavigatorContent> mData = new LinkedHashMap<>();
private final Set<ContentChangeListener> mContentChangeListeners = new HashSet<>();
private View[] mViews;
public HoverMenuAdapter(@NonNull Context context) {
mContext = context;
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));
mTabIds = new ArrayList<>();
for (String tabId : mData.keySet()) {
mTabIds.add(tabId);
}
mViews = new View[mTabIds.size()];
}
@Override
public int getTabCount() {
return mTabIds.size();
}
@Override
public View getTabView(int index) {
mViews[index] = getTabViewInner(index);
return mViews[index];
}
private View getTabViewInner(int index) {
String menuItemId = mTabIds.get(index);
if (ID_MAIN.equals(menuItemId)) {
return createTabView(R.drawable.ic_android_eat_js);
} else if (ID_RECORD.equals(menuItemId)) {
return createTabView(R.drawable.ic_video_record);
} else if (ID_SCRIPT_LIST.equals(menuItemId)) {
return createTabView(R.drawable.ic_menu);
} else {
throw new RuntimeException("Unknown tab selected: " + index);
}
}
@Override
public long getTabId(int position) {
return position;
}
@Override
public NavigatorContent getNavigatorContent(int index) {
String tabId = mTabIds.get(index);
return mData.get(tabId);
}
@Override
public void addContentChangeListener(@NonNull ContentChangeListener listener) {
mContentChangeListeners.add(listener);
}
@Override
public void removeContentChangeListener(@NonNull ContentChangeListener listener) {
mContentChangeListeners.remove(listener);
}
public void selectTab(String id) {
int i = mTabIds.indexOf(id);
mViews[i].performClick();
}
protected void notifyDataSetChanged() {
for (ContentChangeListener listener : mContentChangeListeners) {
listener.onContentChange(this);
}
}
private View createTabView(@DrawableRes int tabBitmapRes) {
return createTabView(tabBitmapRes, ThemeColorManagerCompat.getColorPrimary(), Color.WHITE);
}
private View createTabView(@DrawableRes int tabBitmapRes, @ColorInt int backgroundColor, @ColorInt Integer iconColor) {
Resources resources = mContext.getResources();
int padding = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 8, resources.getDisplayMetrics());
DemoTabView view = new DemoTabView(mContext, resources.getDrawable(R.drawable.tab_background), resources.getDrawable(tabBitmapRes));
view.setTabBackgroundColor(backgroundColor);
view.setTabForegroundColor(iconColor);
view.setPadding(padding, padding, padding, padding);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
view.setElevation(padding);
}
return view;
}
public class DemoTabView extends View {
private int mBackgroundColor;
private Integer mForegroundColor;
private Drawable mCircleDrawable;
private Drawable mIconDrawable;
private int mIconInsetLeft, mIconInsetTop, mIconInsetRight, mIconInsetBottom;
public DemoTabView(Context context, Drawable backgroundDrawable, Drawable iconDrawable) {
super(context);
mCircleDrawable = backgroundDrawable;
mIconDrawable = iconDrawable;
init();
}
private void init() {
int insetsDp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 10, getContext().getResources().getDisplayMetrics());
mIconInsetLeft = mIconInsetTop = mIconInsetRight = mIconInsetBottom = insetsDp;
}
public void setTabBackgroundColor(@ColorInt int backgroundColor) {
mBackgroundColor = backgroundColor;
mCircleDrawable.setColorFilter(mBackgroundColor, PorterDuff.Mode.SRC_ATOP);
}
public void setTabForegroundColor(@ColorInt Integer foregroundColor) {
mForegroundColor = foregroundColor;
if (null != mForegroundColor) {
mIconDrawable.setColorFilter(mForegroundColor, PorterDuff.Mode.SRC_ATOP);
} else {
mIconDrawable.setColorFilter(null);
}
}
public void setIcon(@Nullable Drawable icon) {
mIconDrawable = icon;
if (null != mForegroundColor && null != mIconDrawable) {
mIconDrawable.setColorFilter(mForegroundColor, PorterDuff.Mode.SRC_ATOP);
}
updateIconBounds();
invalidate();
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
// Make circle as large as View minus padding.
mCircleDrawable.setBounds(getPaddingLeft(), getPaddingTop(), w - getPaddingRight(), h - getPaddingBottom());
// Re-size the icon as necessary.
updateIconBounds();
invalidate();
}
private void updateIconBounds() {
if (null != mIconDrawable) {
Rect bounds = new Rect(mCircleDrawable.getBounds());
bounds.set(bounds.left + mIconInsetLeft, bounds.top + mIconInsetTop, bounds.right - mIconInsetRight, bounds.bottom - mIconInsetBottom);
mIconDrawable.setBounds(bounds);
}
}
@Override
protected void onDraw(Canvas canvas) {
mCircleDrawable.draw(canvas);
if (null != mIconDrawable) {
mIconDrawable.draw(canvas);
}
}
}
}

View File

@@ -0,0 +1,191 @@
package com.stardust.scriptdroid.external.floating_window;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.IBinder;
import android.support.annotation.Nullable;
import android.util.Log;
import android.view.View;
import android.view.WindowManager;
import com.stardust.hover.HoverMenuBuilder;
import com.stardust.hover.SimpleHoverMenuTransitionListener;
import com.stardust.hover.WindowHoverMenu;
import com.stardust.scriptdroid.external.floating_window.view.FloatingLayoutBoundsView;
import com.stardust.scriptdroid.external.floating_window.view.FloatingLayoutHierarchyView;
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
import com.stardust.theme.ThemeColorManagerCompat;
import com.stardust.util.MessageEvent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.lang.ref.WeakReference;
import io.mattcarroll.hover.HoverMenu;
import io.mattcarroll.hover.defaulthovermenu.window.WindowViewController;
/**
* Created by Stardust on 2017/3/11.
*/
public class HoverMenuService extends Service {
public static final String MESSAGE_SHOW_AND_EXPAND_MENU = "MESSAGE_SHOW_AND_EXPAND_MENU";
public static final String MESSAGE_SHOW_LAYOUT_HIERARCHY = "MESSAGE_SHOW_LAYOUT_HIERARCHY";
public static final String MESSAGE_SHOW_LAYOUT_BOUNDS = "MESSAGE_SHOW_LAYOUT_BOUNDS";
public static final String MESSAGE_COLLAPSE_MENU = "MESSAGE_COLLAPSE_MENU";
public static final String MESSAGE_MENU_COLLAPSING = "MESSAGE_MENU_COLLAPSING";
private static WeakReference<HoverMenuService> service;
public static boolean isServiceRunning() {
return service != null && service.get() != null;
}
public static void stopService() {
if (isServiceRunning()) {
service.get().stopSelf();
}
}
private static final String TAG = "HoverMenuService";
private static final String PREF_FILE = "hover_menu";
private static final String PREF_HOVER_MENU_VISUAL_STATE = "hover_menu_visual_state";
private boolean mIsRunning;
private SharedPreferences mPrefs;
private WindowViewController mWindowViewController;
private FloatingLayoutHierarchyView mFloatingLayoutHierarchyView;
private FloatingLayoutBoundsView mFloatingLayoutBoundsView;
private WindowHoverMenu mWindowHoverMenu;
private HoverMenu.OnExitListener mWindowHoverMenuMenuExitListener = new HoverMenu.OnExitListener() {
@Override
public void onExitByUserRequest() {
savePreferredLocation();
mWindowHoverMenu.hide();
stopSelf();
}
};
@Override
public void onCreate() {
super.onCreate();
if (isServiceRunning()) {
stopSelf();
} else {
service = new WeakReference<>(this);
}
EventBus.getDefault().register(this);
mPrefs = getSharedPreferences(PREF_FILE, Context.MODE_PRIVATE);
initViews();
}
private void initViews() {
mFloatingLayoutHierarchyView = new FloatingLayoutHierarchyView(this);
mFloatingLayoutBoundsView = new FloatingLayoutBoundsView(this);
initWindowMenu();
mWindowViewController.addView(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, true, mFloatingLayoutHierarchyView);
mWindowViewController.addView(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, true, mFloatingLayoutBoundsView);
}
private void initWindowMenu() {
mWindowHoverMenu = (WindowHoverMenu) new HoverMenuBuilder(this)
.displayWithinWindow()
.useAdapter(new HoverMenuAdapter(this))
.restoreVisualState(loadPreferredLocation())
.build();
mWindowHoverMenu.getHoverMenuView().setContentBackgroundColor(ThemeColorManagerCompat.getColorPrimary());
mWindowHoverMenu.addOnExitListener(mWindowHoverMenuMenuExitListener);
mWindowViewController = mWindowHoverMenu.getWindowViewController();
mWindowHoverMenu.setHoverMenuTransitionListener(new SimpleHoverMenuTransitionListener() {
@Override
public void onExpanding() {
captureCurrentWindow();
}
@Override
public void onCollapsing() {
LayoutInspector.getInstance().clearCapture();
EventBus.getDefault().post(new MessageEvent(MESSAGE_MENU_COLLAPSING));
}
});
}
private void captureCurrentWindow() {
NodeInfo nodeInfo = LayoutInspector.getInstance().captureCurrentWindow();
if (nodeInfo == null)
return;
mFloatingLayoutHierarchyView.setRootNode(nodeInfo);
mFloatingLayoutBoundsView.setRootNode(nodeInfo);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (!mIsRunning) {
mIsRunning = true;
mWindowHoverMenu.show();
}
return START_STICKY;
}
@Override
public void onDestroy() {
mWindowHoverMenu.hide();
mIsRunning = false;
if (isServiceRunning() && service.get() == this)
service.clear();
}
private void savePreferredLocation() {
String memento = mWindowHoverMenu.getVisualState();
mPrefs.edit().putString(PREF_HOVER_MENU_VISUAL_STATE, memento).apply();
}
private String loadPreferredLocation() {
return mPrefs.getString(PREF_HOVER_MENU_VISUAL_STATE, null);
}
@Subscribe
public void onMessageEvent(MessageEvent event) {
switch (event.message) {
case MESSAGE_SHOW_AND_EXPAND_MENU:
mWindowHoverMenu.show();
break;
case MESSAGE_SHOW_LAYOUT_HIERARCHY:
mWindowHoverMenu.hide();
showView(mFloatingLayoutHierarchyView);
break;
case MESSAGE_SHOW_LAYOUT_BOUNDS:
mWindowHoverMenu.hide();
showView(mFloatingLayoutBoundsView);
break;
case MESSAGE_COLLAPSE_MENU:
mWindowHoverMenu.collapseMenu();
break;
}
}
private void showView(View view) {
view.setVisibility(View.VISIBLE);
mWindowViewController.makeTouchable(view);
}
}

View File

@@ -0,0 +1,82 @@
package com.stardust.scriptdroid.external.floating_window.content;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.Toast;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
import com.stardust.scriptdroid.layout_inspector.LayoutInspector;
import com.stardust.util.MessageEvent;
import com.stardust.view.ViewBinder;
import com.stardust.view.ViewBinding;
import org.greenrobot.eventbus.EventBus;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import io.mattcarroll.hover.Navigator;
import io.mattcarroll.hover.NavigatorContent;
import io.mattcarroll.hover.defaulthovermenu.menus.Menu;
import io.mattcarroll.hover.defaulthovermenu.menus.MenuAction;
import io.mattcarroll.hover.defaulthovermenu.menus.MenuItem;
import io.mattcarroll.hover.defaulthovermenu.menus.MenuListNavigatorContent;
/**
* Created by Stardust on 2017/3/12.
*/
public class MainMenuNavigatorContent implements NavigatorContent {
private View mView;
public MainMenuNavigatorContent(Context context) {
mView = View.inflate(context, R.layout.floating_window_main_menu, null);
ViewBinder.bind(this);
}
@ViewBinding.Click(R.id.layout_hierarchy)
private void showLayoutHierarchy() {
if (LayoutInspector.getInstance().getCapture() == null) {
Toast.makeText(mView.getContext(), R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
} else {
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_HIERARCHY));
}
}
@ViewBinding.Click(R.id.layout_bounds)
private void showLayoutBounds() {
if (LayoutInspector.getInstance().getCapture() == null) {
Toast.makeText(mView.getContext(), R.string.text_no_accessibility_permission_to_capture, Toast.LENGTH_SHORT).show();
} else {
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_LAYOUT_BOUNDS));
}
}
@NonNull
@Override
public View getView() {
return mView;
}
@Override
public void onShown(@NonNull Navigator navigator) {
}
@Override
public void onHidden() {
}
public View findViewById(int id) {
return mView.findViewById(id);
}
}

View File

@@ -0,0 +1,40 @@
package com.stardust.scriptdroid.external.floating_window.content;
import android.content.Context;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.ImageView;
import com.stardust.scriptdroid.R;
import io.mattcarroll.hover.Navigator;
import io.mattcarroll.hover.NavigatorContent;
/**
* Created by Stardust on 2017/3/12.
*/
public class RecordNavigatorContent implements NavigatorContent {
private View mView;
public RecordNavigatorContent(Context context) {
mView = new View(context);
}
@NonNull
@Override
public View getView() {
return mView;
}
@Override
public void onShown(@NonNull Navigator navigator) {
}
@Override
public void onHidden() {
}
}

View File

@@ -0,0 +1,43 @@
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.R;
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
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(SharedPrefScriptFileList.getInstance());
}
@NonNull
@Override
public View getView() {
return mFloatingScriptFileListView;
}
@Override
public void onShown(@NonNull Navigator navigator) {
}
@Override
public void onHidden() {
}
}

View File

@@ -0,0 +1,75 @@
package com.stardust.scriptdroid.external.floating_window.view;
import android.content.Context;
import android.graphics.Color;
import android.view.KeyEvent;
import android.view.WindowManager;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.Theme;
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
import com.stardust.scriptdroid.layout_inspector.view.LayoutBoundsView;
import com.stardust.scriptdroid.layout_inspector.view.NodeInfoView;
import com.stardust.scriptdroid.layout_inspector.view.OnNodeInfoSelectListener;
import com.stardust.util.MessageEvent;
import org.greenrobot.eventbus.EventBus;
/**
* Created by Stardust on 2017/3/12.
*/
public class FloatingLayoutBoundsView extends LayoutBoundsView {
private MaterialDialog mNodeInfoDialog;
private NodeInfoView mNodeInfoView;
public FloatingLayoutBoundsView(Context context) {
super(context);
init();
}
private void init() {
setOnNodeInfoSelectListener(new OnNodeInfoSelectListener() {
@Override
public void onNodeSelect(NodeInfo info) {
showNodeInfo(info);
}
});
setBackgroundColor(0x66000000);
setVisibility(GONE);
getPaint().setColor(0xFF222222);
getPaint().setStrokeWidth(2f);
}
private void showNodeInfo(NodeInfo info) {
ensureDialog();
mNodeInfoView.setNodeInfo(info);
mNodeInfoDialog.show();
}
private void ensureDialog() {
if (mNodeInfoDialog == null) {
mNodeInfoView = new NodeInfoView(getContext());
mNodeInfoDialog = new MaterialDialog.Builder(getContext())
.customView(mNodeInfoView, false)
.theme(Theme.LIGHT)
.build();
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_AND_EXPAND_MENU));
setVisibility(GONE);
return true;
}
return super.dispatchKeyEvent(event);
}
}

View File

@@ -0,0 +1,79 @@
package com.stardust.scriptdroid.external.floating_window.view;
import android.content.Context;
import android.content.DialogInterface;
import android.util.Log;
import android.view.KeyEvent;
import android.view.View;
import android.view.WindowManager;
import com.afollestad.materialdialogs.MaterialDialog;
import com.afollestad.materialdialogs.Theme;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
import com.stardust.scriptdroid.layout_inspector.NodeInfo;
import com.stardust.scriptdroid.layout_inspector.view.LayoutHierarchyView;
import com.stardust.scriptdroid.layout_inspector.view.NodeInfoView;
import com.stardust.scriptdroid.layout_inspector.view.OnNodeInfoSelectListener;
import com.stardust.util.MessageEvent;
import org.greenrobot.eventbus.EventBus;
/**
* Created by Stardust on 2017/3/12.
*/
public class FloatingLayoutHierarchyView extends LayoutHierarchyView {
private static final String TAG = "FloatingHierarchyView";
private MaterialDialog mNodeInfoDialog;
private NodeInfoView mNodeInfoView;
public FloatingLayoutHierarchyView(Context context) {
super(context);
init();
}
private void init() {
setBackgroundColor(0x99ffffff);
setVisibility(GONE);
setShowClickedNodeBounds(true);
getBoundsPaint().setStrokeWidth(3);
getBoundsPaint().setColor(0xFFD32F2F);
setOnNodeInfoLongClickListener(new OnNodeInfoSelectListener() {
@Override
public void onNodeSelect(NodeInfo info) {
showNodeInfo(info);
}
});
}
private void showNodeInfo(NodeInfo info) {
ensureDialog();
mNodeInfoView.setNodeInfo(info);
mNodeInfoDialog.show();
}
private void ensureDialog() {
if (mNodeInfoDialog == null) {
mNodeInfoView = new NodeInfoView(getContext());
mNodeInfoDialog = new MaterialDialog.Builder(getContext())
.customView(mNodeInfoView, false)
.theme(Theme.LIGHT)
.build();
mNodeInfoDialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
}
}
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_SHOW_AND_EXPAND_MENU));
setVisibility(GONE);
return true;
}
return super.dispatchKeyEvent(event);
}
}

View File

@@ -0,0 +1,215 @@
package com.stardust.scriptdroid.external.floating_window.view;
import android.content.Context;
import android.os.Environment;
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;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.TextView;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
import com.stardust.scriptdroid.droid.script.file.ScriptFileList;
import com.stardust.scriptdroid.external.floating_window.HoverMenuService;
import com.stardust.scriptdroid.tool.ViewTool;
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperation;
import com.stardust.scriptdroid.ui.main.operation.ScriptFileOperationPopupMenu;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import com.stardust.util.MessageEvent;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.List;
/**
* Created by Stardust on 2017/3/12.
*/
public class FloatingScriptFileListView extends RecyclerView {
private ScriptFileList mScriptFileList;
private final OnClickListener mOnItemClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
int position = getChildViewHolder(v).getAdapterPosition();
onItemClicked(v, position);
}
};
private final OnClickListener mOnEditIconClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
int position = getChildViewHolder((View) v.getParent()).getAdapterPosition();
onEditIconClick(v, position);
}
};
private final OnClickListener mOnMoreIconClickListener = new OnClickListener() {
@Override
public void onClick(View v) {
mOperateFileIndex = getChildViewHolder((View) v.getParent()).getAdapterPosition();
showOrDismissOperationPopupMenu(v);
}
};
private ScriptFileOperationPopupMenu mScriptFileOperationPopupMenu;
private int mOperateFileIndex;
public FloatingScriptFileListView(Context context) {
super(context);
init();
}
private void init() {
setAdapter(new Adapter());
setLayoutManager(new LinearLayoutManager(getContext()));
addItemDecoration(new DividerItemDecoration(getContext(), DividerItemDecoration.VERTICAL));
initScriptFileOperationPopupMenu();
}
@Subscribe
public void showMessage(ScriptFileOperation.ShowMessageEvent event) {
Toast.makeText(getContext(), event.messageResId, Toast.LENGTH_SHORT).show();
}
private void initScriptFileOperationPopupMenu() {
mScriptFileOperationPopupMenu = new ScriptFileOperationPopupMenu(getContext(), getScriptFileOperations());
mScriptFileOperationPopupMenu.setOnItemClickListener(new ScriptFileOperationPopupMenu.OnItemClickListener() {
@Override
public void onClick(View view, int position, ScriptFileOperation operation) {
operation.operate(FloatingScriptFileListView.this, mScriptFileList, mOperateFileIndex);
mScriptFileOperationPopupMenu.dismiss();
if (!(operation instanceof ScriptFileOperation.Rename))
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
}
});
}
protected List<ScriptFileOperation> getScriptFileOperations() {
List<ScriptFileOperation> scriptFileOperations = new ArrayList<>();
scriptFileOperations.add(new ScriptFileOperation.Run());
scriptFileOperations.add(new ScriptFileOperation.Rename() {
@Override
public void operate(final RecyclerView recyclerView, final ScriptFileList scriptFileList, final int position) {
String oldName = scriptFileList.get(position).name;
MaterialDialog dialog = new ThemeColorMaterialDialogBuilder(recyclerView.getContext())
.title(R.string.text_rename)
.checkBoxPrompt(App.getApp().getString(R.string.text_rename_file_meanwhile), false, null)
.input(App.getApp().getString(R.string.text_please_input_new_name), oldName, new MaterialDialog.InputCallback() {
@Override
public void onInput(@NonNull MaterialDialog dialog, CharSequence input) {
scriptFileList.rename(position, input.toString(), dialog.isPromptCheckBoxChecked());
recyclerView.getAdapter().notifyItemChanged(position);
}
})
.build();
dialog.getWindow().setType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT);
dialog.show();
}
});
scriptFileOperations.add(new ScriptFileOperation.OpenByOtherApp());
scriptFileOperations.add(new ScriptFileOperation.CreateShortcut());
scriptFileOperations.add(new ScriptFileOperation.Remove());
scriptFileOperations.add(new ScriptFileOperation.Delete());
return scriptFileOperations;
}
protected void onItemClicked(View v, int position) {
new ScriptFileOperation.Run().operate(this, mScriptFileList, position);
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
}
protected void onEditIconClick(View v, int position) {
new ScriptFileOperation.Edit().operate(this, mScriptFileList, position);
EventBus.getDefault().post(new MessageEvent(HoverMenuService.MESSAGE_COLLAPSE_MENU));
}
public void setScriptFileList(ScriptFileList scriptFileList) {
mScriptFileList = scriptFileList;
getAdapter().notifyDataSetChanged();
}
private void showOrDismissOperationPopupMenu(View v) {
if (mScriptFileOperationPopupMenu.isShowing()) {
mScriptFileOperationPopupMenu.dismiss();
} else {
mScriptFileOperationPopupMenu.show(v);
}
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
EventBus.getDefault().register(this);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
EventBus.getDefault().unregister(this);
}
@Subscribe
public void onMenuCollapsing(MessageEvent event) {
if (event.message.equals(HoverMenuService.MESSAGE_MENU_COLLAPSING) && mScriptFileOperationPopupMenu.isShowing()) {
mScriptFileOperationPopupMenu.dismiss();
}
}
private class Adapter extends RecyclerView.Adapter<ViewHolder> {
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(getContext()).inflate(R.layout.floating_script_list_recycler_view_item, parent, false);
return new ViewHolder(itemView);
}
@Override
public void onBindViewHolder(ViewHolder holder, int position) {
ScriptFile scriptFile = mScriptFileList.get(position);
holder.name.setText(scriptFile.name);
holder.path.setText(trimFilePath(scriptFile.path));
}
private final String SD_CARD_PATH = Environment.getExternalStorageDirectory().toString();
private String trimFilePath(String path) {
if (path.startsWith(SD_CARD_PATH)) {
path = path.substring(SD_CARD_PATH.length());
}
return path;
}
@Override
public int getItemCount() {
return mScriptFileList.size();
}
}
private class ViewHolder extends RecyclerView.ViewHolder {
TextView name, path;
ViewHolder(View itemView) {
super(itemView);
name = (TextView) itemView.findViewById(R.id.name);
path = (TextView) itemView.findViewById(R.id.path);
ViewTool.$(itemView, R.id.edit).setOnClickListener(mOnEditIconClickListener);
ViewTool.$(itemView, R.id.more).setOnClickListener(mOnMoreIconClickListener);
itemView.setOnClickListener(mOnItemClickListener);
}
}
}

View File

@@ -1,97 +0,0 @@
package com.stardust.scriptdroid.external.notification.bounds_assist;
import android.app.Notification;
import android.app.NotificationManager;
import android.content.Context;
import android.preference.PreferenceManager;
import android.support.v4.app.NotificationCompat;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
import com.stardust.util.StateObserver;
/**
* Created by Stardust on 2017/2/2.
*/
public class BoundsAssistSwitchNotification {
private static final int NOTIFY_ID = 11126;
public static final String KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE = "KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE";
private static boolean enable = false;
public static boolean isEnable() {
return enable;
}
static {
App.getStateObserver().register(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, new StateObserver.OnStateChangedListener() {
@Override
public void onStateChanged(boolean newState) {
setEnable(newState);
}
@Override
public void initState(boolean state) {
enable = state;
if (enable) {
showNotification();
}
}
});
App.getStateObserver().register(BoundsAssistant.KEY_BOUNDS_ASSIST_ENABLE, new StateObserver.OnStateChangedListener() {
@Override
public void onStateChanged(boolean newState) {
if (enable) {
setEnable(false);
setEnable(true);
}
}
@Override
public void initState(boolean state) {
}
});
}
public static void setEnable(boolean enable) {
if (BoundsAssistSwitchNotification.enable == enable)
return;
BoundsAssistSwitchNotification.enable = enable;
PreferenceManager.getDefaultSharedPreferences(App.getApp()).edit().putBoolean(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, enable).apply();
if (enable) {
showNotification();
} else {
hideNotification();
}
}
private static void showNotification() {
Notification notification = new NotificationCompat.Builder(App.getApp())
.setAutoCancel(false)
.setSmallIcon(R.drawable.ic_robot_head)
.setDeleteIntent(BoundsAssistSwitchNotificationHandleService.getDeletePendingIntent())
.setContentText(BoundsAssistant.isAssistModeEnable() ?
App.getApp().getString(R.string.text_assist_mode_enabled) :
App.getApp().getString(R.string.text_assist_mode_disabled))
.setContentIntent(BoundsAssistSwitchNotificationHandleService.getStartIntent())
.build();
showNotification(notification);
}
private static void showNotification(Notification notification) {
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.notify(NOTIFY_ID, notification);
}
private static void hideNotification() {
NotificationManager notificationManager = (NotificationManager) App.getApp().getSystemService(Context.NOTIFICATION_SERVICE);
notificationManager.cancel(NOTIFY_ID);
}
}

View File

@@ -1,67 +0,0 @@
package com.stardust.scriptdroid.external.notification.bounds_assist;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.support.annotation.Nullable;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
import static com.stardust.scriptdroid.external.notification.bounds_assist.BoundsAssistSwitchNotification.KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE;
/**
* Created by Stardust on 2017/2/2.
*/
public class BoundsAssistSwitchNotificationHandleService extends Service {
private static final String EXTRA_INTENT_VALID = "BoundsAssistSwitchNotificationHandleService.intentValid";
private static final String EXTRA_ACTION = "action";
private static final int ACTION_TOGGLE_ASSIST_MODE = 1;
private static final int ACTION_CANCEL_ASSIST_MODE_NOTIFICATION = 2;
public static PendingIntent getStartIntent() {
Intent intent = new Intent(App.getApp(), BoundsAssistSwitchNotificationHandleService.class)
.putExtra(EXTRA_INTENT_VALID, true)
.putExtra(EXTRA_ACTION, ACTION_TOGGLE_ASSIST_MODE);
return PendingIntent.getService(App.getApp(), 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
boolean intentValid = intent.getBooleanExtra(EXTRA_INTENT_VALID, false);
if (intentValid) {
performAction(intent.getIntExtra(EXTRA_ACTION, 0));
}
stopSelf();
return super.onStartCommand(intent, flags, startId);
}
private void performAction(int action) {
switch (action) {
case ACTION_TOGGLE_ASSIST_MODE:
BoundsAssistant.setAssistModeEnable(!BoundsAssistant.isAssistModeEnable());
break;
case ACTION_CANCEL_ASSIST_MODE_NOTIFICATION:
App.getStateObserver().setState(KEY_BOUNDS_ASSIST_SWITCH_NOTIFICATION_ENABLE, false);
break;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
public static PendingIntent getDeletePendingIntent() {
Intent deleteIntent = new Intent(App.getApp(), BoundsAssistSwitchNotificationHandleService.class)
.putExtra(EXTRA_INTENT_VALID, true)
.putExtra(EXTRA_ACTION, ACTION_CANCEL_ASSIST_MODE_NOTIFICATION);
return PendingIntent.getService(App.getApp(), 0, deleteIntent, PendingIntent.FLAG_ONE_SHOT);
}
}

View File

@@ -8,9 +8,9 @@ import android.os.IBinder;
import android.support.annotation.Nullable;
import android.widget.Toast;
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
import com.stardust.scriptdroid.App;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.record.AccessibilityRecorderDelegate;
import com.stardust.scriptdroid.service.AccessibilityWatchDogService;
import com.stardust.scriptdroid.service.VolumeChangeListenService;
import com.stardust.scriptdroid.ui.main.MainActivity;

View File

@@ -7,8 +7,8 @@ import android.text.TextUtils;
import android.widget.Toast;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.ui.edit.EditActivity;
import com.stardust.scriptdroid.R;
/**
* Created by Stardust on 2017/2/2.

View File

@@ -8,12 +8,12 @@ import android.text.TextUtils;
import android.widget.Toast;
import com.afollestad.materialdialogs.MaterialDialog;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.script.file.ScriptFile;
import com.stardust.scriptdroid.droid.script.file.SharedPrefScriptFileList;
import com.stardust.scriptdroid.ui.BaseActivity;
import com.stardust.scriptdroid.ui.main.MainActivity;
import com.stardust.theme.dialog.ThemeColorMaterialDialogBuilder;
import com.stardust.scriptdroid.R;
import java.io.File;

View File

@@ -7,8 +7,8 @@ import android.support.annotation.Nullable;
import android.text.TextUtils;
import android.widget.Toast;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.external.shortcut.ShortcutActivity;
import com.stardust.scriptdroid.R;
/**
* Created by Stardust on 2017/2/22.

View File

@@ -6,8 +6,8 @@ import android.os.Bundle;
import android.text.TextUtils;
import android.widget.Toast;
import com.stardust.scriptdroid.R;
import com.stardust.scriptdroid.droid.Droid;
import com.stardust.scriptdroid.R;
import java.io.File;
import java.util.LinkedList;

View File

@@ -1,32 +0,0 @@
package com.stardust.scriptdroid.external.tile;
import android.os.Build;
import android.service.quicksettings.Tile;
import android.service.quicksettings.TileService;
import android.support.annotation.RequiresApi;
import com.stardust.scriptdroid.bounds_assist.BoundsAssistant;
/**
* Created by Stardust on 2017/1/26.
*/
@RequiresApi(api = Build.VERSION_CODES.N)
public class BoundsAssistEnableTileService extends TileService {
public void onClick() {
BoundsAssistant.setAssistModeEnable(!BoundsAssistant.isAssistModeEnable());
updateTile();
}
private void updateTile() {
getQsTile().setState(BoundsAssistant.isAssistModeEnable() ? Tile.STATE_ACTIVE : Tile.STATE_INACTIVE);
getQsTile().updateTile();
}
@Override
public void onStartListening() {
updateTile();
}
}