Skip to content

Commit 53b5db3

Browse files
Update
1 parent ee3ff96 commit 53b5db3

File tree

15 files changed

+741
-0
lines changed

15 files changed

+741
-0
lines changed

androidminidebugger/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/build

androidminidebugger/build.gradle

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
apply plugin: 'com.android.library'
2+
3+
android {
4+
compileSdkVersion 29
5+
buildToolsVersion "29.0.1"
6+
7+
defaultConfig {
8+
minSdkVersion 14
9+
targetSdkVersion 29
10+
vectorDrawables.useSupportLibrary = true
11+
versionCode 1
12+
versionName "1.1.1"
13+
14+
}
15+
16+
buildTypes {
17+
release {
18+
minifyEnabled false
19+
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
20+
}
21+
}
22+
23+
compileOptions {
24+
sourceCompatibility JavaVersion.VERSION_1_8
25+
targetCompatibility JavaVersion.VERSION_1_8
26+
}
27+
28+
}
29+
30+
dependencies {
31+
implementation fileTree(dir: 'libs', include: ['*.jar'])
32+
implementation 'androidx.appcompat:appcompat:1.0.2'
33+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# Add project specific ProGuard rules here.
2+
# You can control the set of applied configuration files using the
3+
# proguardFiles setting in build.gradle.
4+
#
5+
# For more details, see
6+
# http://developer.android.com/guide/developing/tools/proguard.html
7+
8+
# If your project uses WebView with JS, uncomment the following
9+
# and specify the fully qualified class name to the JavaScript interface
10+
# class:
11+
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
12+
# public *;
13+
#}
14+
15+
# Uncomment this to preserve the line number information for
16+
# debugging stack traces.
17+
#-keepattributes SourceFile,LineNumberTable
18+
19+
# If you keep the line number information, uncomment this to
20+
# hide the original source file name.
21+
#-renamesourcefileattribute SourceFile
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools"
4+
package="com.symphonyrecords.debugger">
5+
6+
7+
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
8+
<uses-permission
9+
android:name="android.permission.READ_LOGS"
10+
tools:ignore="ProtectedPermissions" />
11+
12+
<application>
13+
14+
<!--Just for Debugging ( remove this on release)-->
15+
<service android:name=".DebuggerService" />
16+
17+
</application>
18+
19+
20+
</manifest>
Lines changed: 291 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,291 @@
1+
package com.symphonyrecords.debugger;
2+
3+
4+
import android.annotation.SuppressLint;
5+
import android.app.Notification;
6+
import android.app.Service;
7+
import android.content.Context;
8+
import android.content.Intent;
9+
import android.graphics.PixelFormat;
10+
import android.os.Build;
11+
import android.os.IBinder;
12+
import android.text.SpannableString;
13+
import android.text.Spanned;
14+
import android.text.TextUtils;
15+
import android.text.style.ForegroundColorSpan;
16+
import android.util.DisplayMetrics;
17+
import android.view.Gravity;
18+
import android.view.LayoutInflater;
19+
import android.view.MotionEvent;
20+
import android.view.View;
21+
import android.view.ViewGroup;
22+
import android.view.WindowManager;
23+
import android.widget.RelativeLayout;
24+
import android.widget.ScrollView;
25+
import android.widget.TextView;
26+
27+
import androidx.appcompat.widget.AppCompatImageView;
28+
import androidx.core.content.ContextCompat;
29+
30+
import java.lang.ref.WeakReference;
31+
32+
@SuppressLint({"RtlHardcoded", "ClickableViewAccessibility", "InflateParams"})
33+
public class DebuggerService extends Service {
34+
35+
private boolean isMinimized = true;
36+
private boolean isShowing = true;
37+
38+
private WindowManager mWindowManager;
39+
RelativeLayout root_view;
40+
private View mView;
41+
private TextView textView;
42+
private ScrollView scrollView;
43+
private AppCompatImageView btnResize;
44+
private AppCompatImageView btnClose;
45+
private AppCompatImageView btnReset;
46+
private CharSequence msg = "";
47+
private Spanned spanColor;
48+
49+
50+
int paramWidth;
51+
int paramHeight;
52+
float scale;
53+
54+
private static WeakReference<DebuggerService> mWeakReferenceContext;
55+
56+
public static void init(DebuggerService ctx) {
57+
mWeakReferenceContext = new WeakReference<>(ctx);
58+
}
59+
60+
/**
61+
* get WeakReference instance of {@link DebuggerService} class
62+
*/
63+
public static DebuggerService getContext() {
64+
try {
65+
if (null != mWeakReferenceContext && null != mWeakReferenceContext.get()) {
66+
return mWeakReferenceContext.get();
67+
}
68+
} catch (Throwable e) {
69+
e.printStackTrace();
70+
}
71+
return null;
72+
}
73+
74+
75+
@Override
76+
public IBinder onBind(Intent intent) {
77+
return null;
78+
}
79+
80+
@Override
81+
public void onCreate() {
82+
super.onCreate();
83+
84+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
85+
startForeground(1, new Notification());
86+
}
87+
88+
init(this);
89+
90+
DisplayMetrics metrics = getResources().getDisplayMetrics();
91+
paramWidth = (int) (metrics.widthPixels * 0.7f);
92+
paramHeight = (int) (metrics.heightPixels * 0.45f);
93+
94+
scale = metrics.density;
95+
96+
}
97+
98+
@Override
99+
public int onStartCommand(Intent intent, int flags, int startId) {
100+
mWindowManager = (WindowManager) getSystemService(WINDOW_SERVICE);
101+
initUI();
102+
moveView();
103+
return super.onStartCommand(intent, flags, startId);
104+
}
105+
106+
@Override
107+
public void onDestroy() {
108+
try {
109+
if (null != mView && null != mWindowManager) {
110+
mWindowManager.removeView(mView);
111+
mWindowManager = null;
112+
}
113+
} catch (Throwable e) {
114+
e.printStackTrace();
115+
}
116+
117+
118+
super.onDestroy();
119+
}
120+
121+
WindowManager.LayoutParams mWindowsParams;
122+
123+
private void moveView() {
124+
125+
126+
initializeLayoutParams(paramWidth, paramHeight);
127+
128+
129+
mWindowsParams.gravity = Gravity.TOP | Gravity.LEFT;
130+
mWindowsParams.y = 100;
131+
mWindowManager.addView(mView, mWindowsParams);
132+
133+
134+
mView.setOnTouchListener(new View.OnTouchListener() {
135+
136+
private int initialX;
137+
private int initialY;
138+
private float initialTouchX;
139+
private float initialTouchY;
140+
141+
long startTime = System.currentTimeMillis();
142+
143+
144+
@Override
145+
public boolean onTouch(View v, MotionEvent event) {
146+
147+
148+
if (System.currentTimeMillis() - startTime <= 300) {
149+
return false;
150+
}
151+
152+
153+
// switch (event.getAction()) {
154+
switch (event.getActionMasked()) {
155+
156+
case MotionEvent.ACTION_DOWN:
157+
initialX = mWindowsParams.x;
158+
initialY = mWindowsParams.y;
159+
initialTouchX = event.getRawX();
160+
initialTouchY = event.getRawY();
161+
break;
162+
163+
case MotionEvent.ACTION_UP:
164+
break;
165+
166+
case MotionEvent.ACTION_MOVE:
167+
mWindowsParams.x = initialX + (int) (event.getRawX() - initialTouchX);
168+
mWindowsParams.y = initialY + (int) (event.getRawY() - initialTouchY);
169+
mWindowManager.updateViewLayout(mView, mWindowsParams);
170+
break;
171+
}
172+
// mView.invalidate();
173+
return false;
174+
}
175+
});
176+
177+
178+
btnResize.setOnClickListener(view -> {
179+
if (isMinimized) {
180+
initializeLayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT);
181+
btnResize.setImageResource(R.drawable.ic_maximize);
182+
isMinimized = false;
183+
} else {
184+
initializeLayoutParams(paramWidth, paramHeight);
185+
btnResize.setImageResource(R.drawable.ic_minimize);
186+
isMinimized = true;
187+
}
188+
mWindowManager.updateViewLayout(mView, mWindowsParams);
189+
});
190+
191+
192+
mView.findViewById(R.id.btnDrop).setOnClickListener(view -> {
193+
if (isShowing) {
194+
// scrollView.setLayoutParams(new RelativeLayout.LayoutParams(dropSize, dropSize));
195+
btnClose.setVisibility(View.GONE);
196+
btnResize.setVisibility(View.GONE);
197+
btnReset.setVisibility(View.GONE);
198+
root_view.getLayoutParams().width = (int) (55 * scale + 0.5f);
199+
root_view.getLayoutParams().height = (int) (40 * scale + 0.5f);
200+
isShowing = false;
201+
202+
} else {
203+
btnClose.setVisibility(View.VISIBLE);
204+
btnResize.setVisibility(View.VISIBLE);
205+
btnReset.setVisibility(View.VISIBLE);
206+
root_view.getLayoutParams().height = ViewGroup.LayoutParams.MATCH_PARENT;
207+
root_view.getLayoutParams().width = ViewGroup.LayoutParams.WRAP_CONTENT;
208+
btnResize.setImageResource(R.drawable.ic_minimize);
209+
isMinimized = true;
210+
initializeLayoutParams(paramWidth, paramHeight);
211+
isShowing = true;
212+
}
213+
mWindowManager.updateViewLayout(mView, mWindowsParams);
214+
});
215+
216+
217+
}
218+
219+
private void initializeLayoutParams(int width, int height) {
220+
// if you got any problems with FLAG_NOT_FOCUSABLE replace it with FLAG_WATCH_OUTSIDE_TOUCH
221+
// FLAG_WATCH_OUTSIDE_TOUCH will cause keyboard will not pop up and back press will not work
222+
// this is why I replace it with FLAG_NOT_FOCUSABLE
223+
mWindowsParams =
224+
Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
225+
?
226+
new WindowManager.LayoutParams(width, height, WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT)
227+
:
228+
new WindowManager.LayoutParams(width, height, WindowManager.LayoutParams.TYPE_PHONE, WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
229+
}
230+
231+
232+
private void initUI() {
233+
LayoutInflater layoutInflater = (LayoutInflater) getSystemService(Context.LAYOUT_INFLATER_SERVICE);
234+
if (layoutInflater != null) {
235+
mView = layoutInflater.inflate(R.layout.debugger_layout, null);
236+
root_view = mView.findViewById(R.id.root_debugger);
237+
scrollView = mView.findViewById(R.id.scroll_view);
238+
btnResize = mView.findViewById(R.id.btnResize);
239+
btnClose = mView.findViewById(R.id.btnClose);
240+
btnReset = mView.findViewById(R.id.btnReset);
241+
btnClose.setOnClickListener(view -> stopSelf());
242+
btnReset.setOnClickListener(view -> {
243+
if (null != textView) {
244+
textView.setText(null);
245+
}
246+
msg = "";
247+
spanColor = null;
248+
textView = null;
249+
});
250+
}
251+
}
252+
253+
254+
/**
255+
* Don't Change the order of this method code lines.
256+
*/
257+
private void addTextViewToLayout(String text, int textColor) {
258+
spanColor = setSpanColor(text, ContextCompat.getColor(this, textColor));
259+
msg = TextUtils.concat(msg, "\n\n", spanColor);
260+
if (null == textView) {
261+
textView = mView.findViewById(R.id.message_output);
262+
textView.setGravity(Gravity.LEFT);
263+
}
264+
textView.setText(msg);
265+
266+
if (!scrollView.canScrollVertically(1)) {
267+
scrollView.post(() -> {
268+
scrollView.smoothScrollTo(0, scrollView.getHeight());
269+
scrollView.fullScroll(ScrollView.FOCUS_DOWN);
270+
});
271+
}
272+
mWindowManager.updateViewLayout(mView, mWindowsParams);
273+
}
274+
275+
private Spanned setSpanColor(String s, int color) {
276+
SpannableString ss = new SpannableString(s);
277+
ss.setSpan(new ForegroundColorSpan(color), 0, s.length(), 0);
278+
return ss;
279+
}
280+
281+
public static void setDebugText(String msg, int textColor) {
282+
if (null != getContext()) getContext().addTextViewToLayout(msg, textColor);
283+
}
284+
285+
286+
public static void stop() {
287+
if (null != getContext()) getContext().stopSelf();
288+
}
289+
290+
291+
}

0 commit comments

Comments
 (0)