From 1c757c667d4d827cc0bcf692dae663f7ca49b01c Mon Sep 17 00:00:00 2001 From: Runt <qingingrunt2010@qq.com> Date: Sun, 01 May 2022 08:51:00 +0000 Subject: [PATCH] 悬浮窗 位置移动 --- app/src/main/java/com/auto/lyric/MainActivity.java | 77 ++++++-- app/src/main/res/values/strings.xml | 1 app/src/main/res/layout/float_view.xml | 38 +++- app/src/main/AndroidManifest.xml | 25 +++ app/src/main/java/com/auto/lyric/util/DeviceUtil.java | 18 - app/src/main/res/xml/simulateinput.xml | 11 + app/src/main/java/com/auto/lyric/service/FloatingWindowService.java | 108 +++++++++++++ app/src/main/java/com/auto/lyric/widgets/Sentence.java | 25 +++ app/src/main/res/values/colors.xml | 1 app/src/main/java/com/auto/lyric/widgets/LyricView.java | 151 ++++++++++++++++++ 10 files changed, 412 insertions(+), 43 deletions(-) diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 63276b4..3d7d703 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -25,6 +25,7 @@ tools:ignore="ProtectedPermissions" /> <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/> <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" /> + <uses-permission android:name="android.permission.SYSTEM_OVERLAY_WINDOW" /> <uses-permission android:name="android.permission.BIND_ACCESSIBILITY_SERVICE" /> <application android:allowBackup="true" @@ -42,6 +43,30 @@ <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> + <service + android:name=".service.AutoInputService" + android:enabled="true" + android:exported="true" + android:permission="android.permission.BIND_ACCESSIBILITY_SERVICE"> + <intent-filter> + <action android:name="android.accessibilityservice.AccessibilityService" android:resource="@xml/simulateinput" /> + </intent-filter> + <meta-data + android:name="android.accessibilityservice" + android:resource="@xml/simulateinput"/> + </service> + <service + android:name=".service.FloatingWindowService" + android:enabled="true" + android:exported="true" + android:permission="android.permission.SYSTEM_OVERLAY_WINDOW|android.permission.SYSTEM_ALERT_WINDOW"> + <intent-filter> + <action android:name="float.service" /> + </intent-filter> + <meta-data + android:name="android.accessibilityservice" + android:resource="@xml/simulateinput"/> + </service> </application> </manifest> \ No newline at end of file diff --git a/app/src/main/java/com/auto/lyric/MainActivity.java b/app/src/main/java/com/auto/lyric/MainActivity.java index 0340eef..462bbc8 100644 --- a/app/src/main/java/com/auto/lyric/MainActivity.java +++ b/app/src/main/java/com/auto/lyric/MainActivity.java @@ -1,47 +1,58 @@ package com.auto.lyric; import android.content.Intent; +import android.graphics.PixelFormat; import android.net.Uri; import android.os.Build; +import android.os.Handler; +import android.os.Message; import android.provider.Settings; import android.text.TextUtils; import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.View; +import android.view.WindowManager; + +import androidx.annotation.NonNull; import com.auto.lyric.base.activities.BaseActivity; import com.auto.lyric.databinding.ActivityMainBinding; +import com.auto.lyric.databinding.FloatViewBinding; import com.auto.lyric.service.AutoInputService; +import com.auto.lyric.service.FloatingWindowService; import com.auto.lyric.vm.MainViewModel; public class MainActivity extends BaseActivity<ActivityMainBinding, MainViewModel> { - Intent service = new Intent(getApplicationContext(), AutoInputService.class); - @Override public void initViews() { - } + Intent inputService = new Intent(getApplicationContext(), AutoInputService.class); - @Override - protected void onResume() { - super.onResume(); + Intent floatService = new Intent(getApplicationContext(), FloatingWindowService.class); + binding.button.setOnClickListener(v -> { - //申请权限 - if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { - //开启悬浮窗 - if(!Settings.canDrawOverlays(getApplicationContext())) { - //启动Activity让用户授权 - Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); - intent.setData(Uri.parse("package:" + getPackageName())); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK ); - startActivity(intent); - }else if(!isAccessibilitySettingsOn()){//辅助权限 - Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK ); - startActivity(intent); - }else{//开启监听服务 - startService(service); + //申请权限 + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) { + //开启悬浮窗 + /* if(!Settings.canDrawOverlays(getApplicationContext())) { + //启动Activity让用户授权 + Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION); + intent.setData(Uri.parse("package:" + getPackageName())); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK ); + startActivity(intent); + }else if(!isAccessibilitySettingsOn()){//辅助权限 + Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS); + intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK ); + startActivity(intent); + }else{//开启监听服务 + //startService(floatService); + }*/ + startService(floatService); + //showFloatView(); } - } + }); } public boolean isAccessibilitySettingsOn() { @@ -82,5 +93,27 @@ return false; } + private void showFloatView(){ + + + //View view = LayoutInflater.from(this).inflate(R.layout.float_view,null); + FloatViewBinding binding = FloatViewBinding.inflate(getLayoutInflater()); + WindowManager manager = (WindowManager) getApplicationContext().getSystemService(WINDOW_SERVICE); + WindowManager.LayoutParams params = new WindowManager.LayoutParams(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + }else { + params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + } + params.format = PixelFormat.RGBA_8888; + params.gravity = Gravity.CENTER; + params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = WindowManager.LayoutParams.WRAP_CONTENT; + binding.btnBack.setOnClickListener(v ->{ + stopService(new Intent(this,this.getClass())); + }); + manager.addView(binding.getRoot(),params); + } } \ No newline at end of file diff --git a/app/src/main/java/com/auto/lyric/service/FloatingWindowService.java b/app/src/main/java/com/auto/lyric/service/FloatingWindowService.java new file mode 100644 index 0000000..720e9e6 --- /dev/null +++ b/app/src/main/java/com/auto/lyric/service/FloatingWindowService.java @@ -0,0 +1,108 @@ +package com.auto.lyric.service; + +import android.app.Service; +import android.content.Intent; +import android.graphics.PixelFormat; +import android.os.Build; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.util.Log; +import android.view.Gravity; +import android.view.LayoutInflater; +import android.view.MotionEvent; +import android.view.View; +import android.view.WindowManager; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.view.LayoutInflaterFactory; + +import com.auto.lyric.R; +import com.auto.lyric.databinding.FloatViewBinding; +import com.auto.lyric.util.DeviceUtil; + +/** + * 全局悬浮窗 + * Created by Runt (qingingrunt2010@qq.com) on 2022/4/30. + */ +public class FloatingWindowService extends Service { + + private WindowManager manager; + private WindowManager.LayoutParams params; + FloatViewBinding binding; + Handler handler; + final String TAG = "FloatingWindowService"; + + @Override + public void onCreate() { + super.onCreate(); + Log.e(TAG,"onCreate "); + View view = LayoutInflater.from(getBaseContext()).inflate(R.layout.float_view,null); + binding = FloatViewBinding.bind(view); + manager = (WindowManager) getSystemService(WINDOW_SERVICE); + params = new WindowManager.LayoutParams(); + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; + }else { + params.type = WindowManager.LayoutParams.TYPE_SYSTEM_ALERT; + } + params.format = PixelFormat.RGBA_8888; + params.gravity = Gravity.LEFT | Gravity.TOP; + params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; + params.width = WindowManager.LayoutParams.MATCH_PARENT; + params.height = DeviceUtil.convertDpToPixel(200,getBaseContext()); + handler = new Handler(this.getMainLooper()){ + @Override + public void handleMessage(@NonNull Message msg) { + binding.lyric.setText(msg.obj.toString()); + int offset = binding.lyric.getLineCount() * binding.lyric.getLineHeight(); + + } + }; + binding.close.setOnClickListener(v ->{ + stopService(new Intent(this,this.getClass())); + stopService(new Intent(this,AutoInputService.class)); + }); + binding.floating.setOnTouchListener(new View.OnTouchListener() { + int startY; + @Override + public boolean onTouch(View v, MotionEvent event) { + if(event.getAction() == MotionEvent.ACTION_DOWN){ + startY = (int) event.getY(); + + }else if(event.getAction() == MotionEvent.ACTION_MOVE + || event.getAction() == MotionEvent.ACTION_UP){ + params.y = (int) event.getRawY() - DeviceUtil.getStatusBarHeight(getBaseContext()) - startY; + manager.updateViewLayout(binding.getRoot(), params); + Log.e(TAG,"ACTION_MOVE V:"+params.y); + } + Log.e(TAG,"onTouch event:"+event); + Log.e(TAG,"onTouch getRawY:"+event.getRawY()); + return true; + } + }); + + } + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + Log.e(TAG,"onStartCommand flags:"+flags+" startId:"+startId+ " intent:"+intent); + manager.addView(binding.getRoot(),params); + return super.onStartCommand(intent, flags, startId); + } + + @Override + public void onDestroy() { + super.onDestroy(); + Log.e(TAG,"onDestroy "); + manager.removeView(binding.getRoot()); + + } +} diff --git a/app/src/main/java/com/auto/lyric/util/DeviceUtil.java b/app/src/main/java/com/auto/lyric/util/DeviceUtil.java index 2e1bdff..b6128a3 100644 --- a/app/src/main/java/com/auto/lyric/util/DeviceUtil.java +++ b/app/src/main/java/com/auto/lyric/util/DeviceUtil.java @@ -175,20 +175,12 @@ * @return */ public static int getStatusBarHeight(Context context) { - Class<?> c = null; - Object obj = null; - Field field = null; - int x = 0, statusBarHeight = 0; - try { - c = Class.forName("com.android.internal.R$dimen"); - obj = c.newInstance(); - field = c.getField("status_bar_height"); - x = Integer.parseInt(field.get(obj).toString()); - statusBarHeight = context.getResources().getDimensionPixelSize(x); - } catch (Exception e1) { - e1.printStackTrace(); + int result = 0; + int resId = context.getResources().getIdentifier("status_bar_height", "dimen", "android"); + if (resId > 0) { + result = context.getResources().getDimensionPixelOffset(resId); } - return statusBarHeight; + return result; } /** diff --git a/app/src/main/java/com/auto/lyric/widgets/LyricView.java b/app/src/main/java/com/auto/lyric/widgets/LyricView.java new file mode 100644 index 0000000..47c4f82 --- /dev/null +++ b/app/src/main/java/com/auto/lyric/widgets/LyricView.java @@ -0,0 +1,151 @@ +package com.auto.lyric.widgets; + +import android.app.Activity; +import android.content.Context; +import android.graphics.Canvas; +import android.graphics.Color; +import android.graphics.Paint; +import android.graphics.Typeface; +import android.media.MediaPlayer; +import android.os.Bundle; +import android.os.Handler; +import android.util.AttributeSet; +import android.widget.TextView; + +import com.auto.lyric.R; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +/** + * 歌词 + * Created by Runt (qingingrunt2010@qq.com) on 2022/4/30. + */ +public class LyricView extends androidx.appcompat.widget.AppCompatTextView { + private Paint mPaint; + private float mX; + private Paint mPathPaint; + public int index = 0; + private List<Sentence> list; + public float mTouchHistoryY; + private int mY; + private float middleY;// + private static final int DY = 40; // + public LyricView(Context context) { + super(context); + init(); + } + public LyricView(Context context, AttributeSet attr) { + super(context, attr); + init(); + } + public LyricView(Context context, AttributeSet attr, int i) { + super(context, attr, i); + init(); + } + private void init() { + setFocusable(true); + if(list==null){ + list=new ArrayList<Sentence>(); + Sentence sen=new Sentence(0," "); + list.add(0, sen); + } + // + mPaint = new Paint(); + mPaint.setAntiAlias(true); + mPaint.setTextSize(24); + mPaint.setColor(Color.BLACK); + mPaint.setAlpha(80); + mPaint.setTypeface(Typeface.SERIF); + // + mPathPaint = new Paint(); + mPathPaint.setAntiAlias(true); + mPathPaint.setColor(Color.RED); + mPathPaint.setTextSize(24); + mPathPaint.setTypeface(Typeface.SANS_SERIF); + } + protected void onDraw(Canvas canvas) { + super.onDraw(canvas); + canvas.drawColor(0xEFeffff); + Paint p = mPaint; + Paint p2 = mPathPaint; + p.setTextAlign(Paint.Align.LEFT); + if (index == -1) + return; + p2.setTextAlign(Paint.Align.LEFT); + // + canvas.drawText(list.get(index).getName(), mX, middleY, p2); + float tempY = middleY; + // + for (int i = index - 1; i >= 0; i--) { + tempY = tempY - DY; + if (tempY < 0) { + break; + } + canvas.drawText(list.get(i).getName(), mX, tempY, p); + } + tempY = middleY; + // + for (int i = index + 1; i < list.size(); i++) { + // + tempY = tempY + DY; + if (tempY > mY) { + break; + } + canvas.drawText(list.get(i).getName(), mX, tempY, p); + } + } + protected void onSizeChanged(int w, int h, int ow, int oh) { + super.onSizeChanged(w, h, ow, oh); + mX = w * 0.3f; + mY = h; + middleY = h * 0.5f; + } + public long updateIndex(int index) { + if (index == -1) + return -1; + this.index=index; + return index; + } + public List<Sentence> getList() { + return list; + } + public void setList(List<Sentence> list) { + this.list = list; + } + public void updateUI(){ + new Thread(new updateThread()).start(); + } + class updateThread implements Runnable { + long time = 300; + int i=0; + public void run() { + while (true) { + long sleeptime = updateIndex(i); + time += sleeptime; + mHandler.post(mUpdateResults); + if (sleeptime == -1) + return; + try { + Thread.sleep(time); + i++; + if(i==getList().size()) + { + i=0; + time = 300; + } + } catch (InterruptedException e) { + e.printStackTrace(); + } + } + } + } + Handler mHandler = new Handler(); + Runnable mUpdateResults = new Runnable() { + public void run() { + invalidate(); // + } + }; +} diff --git a/app/src/main/java/com/auto/lyric/widgets/Sentence.java b/app/src/main/java/com/auto/lyric/widgets/Sentence.java new file mode 100644 index 0000000..f2cdf69 --- /dev/null +++ b/app/src/main/java/com/auto/lyric/widgets/Sentence.java @@ -0,0 +1,25 @@ +package com.auto.lyric.widgets; + +/** + * Created by Runt (qingingrunt2010@qq.com) on 2022/4/30. + */ +public class Sentence { + private String name; + private int index; + public Sentence(int index,String name){ + this.name=name; + this.index=index; + } + public String getName() { + return name; + } + public void setName(String name) { + this.name = name; + } + public int getIndex() { + return index; + } + public void setIndex(int index) { + this.index = index; + } +} \ No newline at end of file diff --git a/app/src/main/res/layout/float_view.xml b/app/src/main/res/layout/float_view.xml index 39a9218..df671b9 100644 --- a/app/src/main/res/layout/float_view.xml +++ b/app/src/main/res/layout/float_view.xml @@ -2,45 +2,67 @@ <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:background="@color/black_trans" xmlns:app="http://schemas.android.com/apk/res-auto"> - <com.google.android.material.floatingactionbutton.FloatingActionButton + <ImageButton android:id="@+id/floating" android:layout_width="40dp" android:layout_height="wrap_content" android:alpha="0.9" + android:src="@android:drawable/ic_notification_overlay" app:layout_constraintTop_toTopOf="parent" - app:layout_constraintLeft_toLeftOf="parent" /> + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintBottom_toTopOf="@id/lyric"/> + <ImageButton + android:id="@+id/close" + android:layout_width="40dp" + android:layout_height="wrap_content" + android:alpha="0.9" + android:src="@android:drawable/ic_menu_close_clear_cancel" + app:layout_constraintTop_toTopOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintBottom_toTopOf="@id/lyric"/> + <com.auto.lyric.widgets.LyricView + android:id="@+id/lyric" + android:layout_width="match_parent" + android:layout_height="0dp" + android:text="歌词大意" + android:gravity="center" + app:layout_constraintLeft_toLeftOf="parent" + app:layout_constraintRight_toRightOf="parent" + app:layout_constraintTop_toBottomOf="@id/close" + app:layout_constraintBottom_toTopOf="@id/btn_back"/> - <com.google.android.material.button.MaterialButton + <Button android:id="@+id/btn_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="后退" android:textColor="@color/black" - android:alpha="0.2" + app:layout_constraintTop_toBottomOf="@id/lyric" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toLeftOf="parent"/> - <com.google.android.material.button.MaterialButton + <Button android:id="@+id/btn_pause" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="暂停" android:textColor="@color/black" - android:alpha="0.2" + app:layout_constraintTop_toBottomOf="@id/lyric" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintLeft_toRightOf="@id/btn_back" app:layout_constraintRight_toLeftOf="@id/btn_fast"/> - <com.google.android.material.button.MaterialButton + <Button android:id="@+id/btn_fast" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="快进" android:textColor="@color/black" - android:alpha="0.2" + app:layout_constraintTop_toBottomOf="@id/lyric" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintRight_toRightOf="parent"/> </androidx.constraintlayout.widget.ConstraintLayout> \ No newline at end of file diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 78793ab..bf695cb 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -6,6 +6,7 @@ <color name="teal_200">#FF03DAC5</color> <color name="teal_700">#FF018786</color> <color name="black">#FF000000</color> + <color name="black_trans">#61000000</color> <color name="white">#FFFFFFFF</color> diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index e5f8fdc..d90fc92 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,2 +1,3 @@ <resources> + <string name="simulate_input_description">simulate_input</string> </resources> \ No newline at end of file diff --git a/app/src/main/res/xml/simulateinput.xml b/app/src/main/res/xml/simulateinput.xml new file mode 100644 index 0000000..7224cff --- /dev/null +++ b/app/src/main/res/xml/simulateinput.xml @@ -0,0 +1,11 @@ +<?xml version="1.0" encoding="utf-8"?> +<accessibility-service + xmlns:android="http://schemas.android.com/apk/res/android" + android:accessibilityEventTypes="typeAllMask" + android:accessibilityFeedbackType="feedbackGeneric" + android:accessibilityFlags="flagReportViewIds|flagRetrieveInteractiveWindows" + android:canRetrieveWindowContent="true" + android:description="@string/simulate_input_description" + android:packageNames="com.ss.android.ugc.aweme" + android:notificationTimeout="1" + /> \ No newline at end of file -- Gitblit v1.9.1