- * Modified by Stardust on 2017/3/10
- *
- * @author Eric Bhatti
- * @since 24 November, 2015
- */
-public class Floaty {
-
- public interface FloatyOrientationListener {
-
-
- /**
- * This method is called before the orientation change happens, you can use this to save the data of your views so you can later populate the data back in {@link #afterOrientationChange}
- *
- * @param floaty The floating window
- */
- public void beforeOrientationChange(Floaty floaty);
-
- /**
- * This method is called after the orientation change happens, you can use this to restore the data of your views that you saved in {@link #beforeOrientationChange}
- *
- * @param floaty The floating window
- */
- public void afterOrientationChange(Floaty floaty);
-
- }
-
-
- public interface OnBackPressedListener {
- boolean onBackPressed();
- }
-
- private View.OnClickListener mOnHeadClickListener;
-
-
- private OnBackPressedListener mOnBackPressedListener;
-
- private final View head;
- private final View body;
- private final Context context;
- private final Notification notification;
- private final int notificationId;
- private static Floaty floaty;
- private final FloatyOrientationListener floatyOrientationListener;
- private float ratioY = 0;
- private float oldWidth = 0;
- private float oldX = 0;
- private boolean confChange = false;
-
- private static final String LOG_TAG = "Floaty";
-
-
- /**
- * @return The body of the floaty which is assigned through the {@link #createInstance} method.
- */
-
- public View getBody() {
- return floaty.body;
- }
-
-
- /**
- * @return The head of the floaty which is assigned through the {@link #createInstance} method.
- */
-
- public View getHead() {
- return floaty.head;
- }
-
- /**
- * Creates a Singleton of the Floating Window
- *
- * @param context The application context
- * @param head The head View, upon clicking it the body is to be opened
- * @param body The body View
- * @param notificationId The notificationId for your notification
- * @param notification The notification which is displayed for the foreground service
- * @param floatyOrientationListener The {@link FloatyOrientationListener} interface with callbacks which are called when orientation changes.
- * @return A Floating Window
- */
-
- public static synchronized Floaty createInstance(Context context, View head, View body, int notificationId, Notification notification, FloatyOrientationListener
- floatyOrientationListener) {
- if (floaty == null) {
- floaty = new Floaty(context, head, body, notificationId, notification, floatyOrientationListener);
- }
- return floaty;
- }
-
- /**
- * Creates a Singleton of the Floating Window
- *
- * @param context The application context
- * @param head The head View, upon clicking it the body is to be opened
- * @param body The body View
- * @param notificationId The notificationId for your notification
- * @param notification The notification which is displayed for the foreground service
- * @return A Floating Window
- */
- public static synchronized Floaty createInstance(Context context, View head, View body, int notificationId, Notification notification) {
- if (floaty == null) {
- floaty = new Floaty(context, head, body, notificationId, notification, new FloatyOrientationListener() {
- @Override
- public void beforeOrientationChange(Floaty floaty) {
- Log.d(LOG_TAG, "beforeOrientationChange");
- }
-
- @Override
- public void afterOrientationChange(Floaty floaty) {
- Log.d(LOG_TAG, "afterOrientationChange");
- }
- });
- }
- return floaty;
- }
-
- public static synchronized Floaty createInstance(Context context, View head, View body) {
- return createInstance(context, head, body, -1, null);
- }
-
- /**
- * @return The same instance of Floating Window, which has been created through {@link #createInstance}. Don't call this method before createInstance
- */
- public static synchronized Floaty getInstance() {
- if (floaty == null) {
- throw new NullPointerException("Floaty not initialized! First call createInstance method, then to access Floaty in any other class call getDefault()");
- }
- return floaty;
- }
-
- private Floaty(Context context, View head, View body, int notificationId, Notification notification, FloatyOrientationListener floatyOrientationListener) {
- this.head = head;
- this.body = body;
- this.context = context;
- this.notification = notification;
- this.notificationId = notificationId;
- this.floatyOrientationListener = floatyOrientationListener;
- }
-
-
- /**
- * Starts the service and adds it to the screen
- */
- public void startService() {
- Intent intent = new Intent(context, Floaty.FloatHeadService.class);
- context.startService(intent);
- }
-
- /**
- * Stops the service and removes it from the screen
- */
- public void stopService() {
- Intent intent = new Intent(context, Floaty.FloatHeadService.class);
- context.stopService(intent);
- }
-
-
- public void setOnHeadClickListener(View.OnClickListener onHeadClickListener) {
- mOnHeadClickListener = onHeadClickListener;
- }
-
- public void setOnBackPressedListener(OnBackPressedListener onBackPressedListener) {
- mOnBackPressedListener = onBackPressedListener;
- }
-
- /**
- * Helper method for notification creation.
- *
- * @param context
- * @param contentTitle
- * @param contentText
- * @param notificationIcon
- * @param contentIntent
- * @return Notification for the Service
- */
- public static Notification createNotification(Context context, String contentTitle, String contentText, int notificationIcon, PendingIntent contentIntent) {
- return new NotificationCompat.Builder(context)
- .setContentTitle(contentTitle)
- .setContentText(contentText)
- .setSmallIcon(notificationIcon)
- .setContentIntent(contentIntent).build();
-
- }
-
- public static class FloatHeadService extends Service {
-
- private WindowManager windowManager;
- private WindowManager.LayoutParams params;
- private LinearLayout mLinearLayout;
- GestureDetectorCompat gestureDetectorCompat;
- DisplayMetrics metrics;
- private boolean didFling;
- private int[] clickLocation = new int[2];
-
-
- @Nullable
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
-
- @Override
- public void onConfigurationChanged(Configuration newConfig) {
- if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE || newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
-
- int[] location = new int[2];
- mLinearLayout.getLocationOnScreen(location);
- floaty.oldWidth = metrics.widthPixels;
- floaty.confChange = true;
- if (floaty.getBody().getVisibility() == View.VISIBLE) {
- floaty.oldX = clickLocation[0];
- floaty.ratioY = (float) (clickLocation[1]) / (float) metrics.heightPixels;
- } else {
- floaty.oldX = location[0];
- floaty.ratioY = (float) (location[1]) / (float) metrics.heightPixels;
- }
- floaty.floatyOrientationListener.beforeOrientationChange(floaty);
- floaty.stopService();
- floaty.startService();
- floaty.floatyOrientationListener.afterOrientationChange(floaty);
- }
- }
-
- public int onStartCommand(Intent intent, int flags, int startId) {
- Log.d(LOG_TAG, "onStartCommand");
- metrics = new DisplayMetrics();
- windowManager.getDefaultDisplay().getMetrics(metrics);
- if (floaty.notification != null)
- startForeground(floaty.notificationId, floaty.notification);
- return START_STICKY;
- }
-
- private void showHead() {
- floaty.head.setVisibility(View.VISIBLE);
- floaty.body.setVisibility(View.GONE);
- params.x = clickLocation[0];
- params.y = clickLocation[1] - 36;
- params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- params.width = WindowManager.LayoutParams.WRAP_CONTENT;
- params.height = WindowManager.LayoutParams.WRAP_CONTENT;
- mLinearLayout.setBackgroundColor(Color.argb(0, 0, 0, 0));
- windowManager.updateViewLayout(mLinearLayout, params);
- }
-
- @Override
- public void onCreate() {
- super.onCreate();
- Log.d(LOG_TAG, "onCreate");
- mLinearLayout = new LinearLayout(getApplicationContext()) {
- @Override
- public boolean dispatchKeyEvent(KeyEvent event) {
- if (event.getKeyCode() == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_UP) {
- if (floaty.mOnBackPressedListener != null && !floaty.mOnBackPressedListener.onBackPressed()) {
- showHead();
- return true;
- }
- }
- if (event.getKeyCode() == KeyEvent.KEYCODE_HOME) {
- showHead();
- return true;
- }
- return super.dispatchKeyEvent(event);
- }
- };
-
- gestureDetectorCompat = new GestureDetectorCompat(floaty.context, new GestureDetector.SimpleOnGestureListener() {
- private int initialX;
- private int initialY;
- private float initialTouchX;
- private float initialTouchY;
-
- @Override
- public boolean onDown(MotionEvent event) {
- Log.d(LOG_TAG, "onDown");
- initialX = params.x;
- initialY = params.y;
- initialTouchX = event.getRawX();
- initialTouchY = event.getRawY();
- didFling = false;
- return false;
- }
-
- @Override
- public void onShowPress(MotionEvent e) {
- Log.d(LOG_TAG, "onShowPress");
- floaty.head.setAlpha(0.8f);
- }
-
- @Override
- public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
- if (floaty.body.getVisibility() == View.VISIBLE) {
- floaty.body.setVisibility(View.GONE);
- params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- params.width = WindowManager.LayoutParams.WRAP_CONTENT;
- params.height = WindowManager.LayoutParams.WRAP_CONTENT;
- mLinearLayout.setBackgroundColor(Color.argb(0, 0, 0, 0));
- }
- params.x = (initialX + (int) ((e2.getRawX() - initialTouchX)));
- params.y = (initialY + (int) ((e2.getRawY() - initialTouchY)));
- windowManager.updateViewLayout(mLinearLayout, params);
- return false;
- }
-
- @Override
- public boolean onSingleTapConfirmed(MotionEvent e) {
- Log.d(LOG_TAG, "onSingleTapConfirmed");
- if (floaty.body.getVisibility() == View.GONE) {
- params.x = metrics.widthPixels;
- params.y = 0;
- params.flags = params.flags & ~WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- params.width = WindowManager.LayoutParams.MATCH_PARENT;
- params.height = WindowManager.LayoutParams.MATCH_PARENT;
- //floaty.head.getLocationOnScreen(clickLocation);
- floaty.head.setVisibility(View.GONE);
- floaty.body.setVisibility(View.VISIBLE);
- mLinearLayout.setBackgroundColor(Color.argb(200, 50, 50, 50));
- } else {
- floaty.body.setVisibility(View.GONE);
- floaty.head.setVisibility(View.VISIBLE);
- params.x = clickLocation[0];
- params.y = clickLocation[1] - 36;
- params.width = WindowManager.LayoutParams.WRAP_CONTENT;
- params.height = WindowManager.LayoutParams.WRAP_CONTENT;
- params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
- mLinearLayout.setBackgroundColor(Color.argb(0, 0, 0, 0));
- }
- windowManager.updateViewLayout(mLinearLayout, params);
- if (floaty.mOnHeadClickListener != null) {
- floaty.mOnHeadClickListener.onClick(floaty.head);
- }
- return false;
- }
-
- @Override
- public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
- Log.d(LOG_TAG, "onFling");
- didFling = true;
- int newX = params.x;
- if (newX > (metrics.widthPixels / 2))
- params.x = metrics.widthPixels;
- else
- params.x = 0;
- windowManager.updateViewLayout(mLinearLayout, params);
- return false;
- }
- });
-
- mLinearLayout.setOrientation(LinearLayout.VERTICAL);
- windowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
- metrics = new DisplayMetrics();
- windowManager.getDefaultDisplay().getMetrics(metrics);
- params = new WindowManager.LayoutParams(
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.WRAP_CONTENT,
- WindowManager.LayoutParams.TYPE_PHONE,
- WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE,
- PixelFormat.TRANSLUCENT);
- params.gravity = Gravity.TOP | Gravity.LEFT;
-
-
- if (floaty.confChange) {
- floaty.confChange = false;
- if (floaty.oldX < (floaty.oldWidth / 2)) {
- params.x = 0;
- } else {
- params.x = metrics.widthPixels;
- }
- params.y = (int) (metrics.heightPixels * floaty.ratioY);
- } else {
- params.x = metrics.widthPixels;
- params.y = 0;
- }
- floaty.body.setVisibility(View.GONE);
- floaty.head.setOnTouchListener(new View.OnTouchListener() {
- @Override
- public boolean onTouch(View v, MotionEvent event) {
- gestureDetectorCompat.onTouchEvent(event);
- if (event.getAction() == MotionEvent.ACTION_UP) {
- floaty.head.setAlpha(1.0f);
- if (!didFling) {
- Log.d(LOG_TAG, "ACTION_UP");
- int newX = params.x;
- if (newX > (metrics.widthPixels / 2))
- params.x = metrics.widthPixels;
- else
- params.x = 0;
- windowManager.updateViewLayout(mLinearLayout, params);
- }
- }
- return true;
- }
- });
- windowManager.addView(mLinearLayout, params);
- if (floaty.body.getParent() != null) {
- ((ViewGroup) floaty.body.getParent()).removeView(floaty.body);
- }
- mLinearLayout.setFocusable(true);
- LinearLayout.LayoutParams headParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
- LinearLayout.LayoutParams bodyParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
- headParams.gravity = Gravity.TOP | Gravity.RIGHT;
- bodyParams.gravity = Gravity.TOP;
- mLinearLayout.addView(floaty.head, headParams);
- mLinearLayout.addView(floaty.body, bodyParams);
- }
-
- public void onDestroy() {
- super.onDestroy();
- if (mLinearLayout != null) {
- mLinearLayout.removeAllViews();
- windowManager.removeView(mLinearLayout);
- }
- stopForeground(true);
- }
- }
-}
\ No newline at end of file
diff --git a/app/src/main/res/xml/accessibility_service_config.xml b/app/src/main/res/xml/accessibility_service_config.xml
index ec4d9dc2..a26caa28 100644
--- a/app/src/main/res/xml/accessibility_service_config.xml
+++ b/app/src/main/res/xml/accessibility_service_config.xml
@@ -1,9 +1,11 @@