Galgo是Android日志类库,用于在屏幕上显示应用的日志信息。这对于测试人员和开发人员非常有用,可以根据屏幕上的日志文件了解应用出现BUG时发生的事情。
可以定义屏幕上显示日志的背景颜色、文本颜色、文本大小和日志显示的行数。
https://github.com/inaka/galgo
public class ExampleActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example);
// add some customization to the log messages
GalgoOptions options = new GalgoOptions.Builder()
.numberOfLines(15)
.backgroundColor(Color.parseColor("#D9d6d6d6"))
.textColor(Color.BLACK)
.textSize(15)
.build();
Galgo.enable(this, options);
Galgo.log("I am a log message");
}
public void onDestroy() {
super.onDestroy();
// always call disable to avoid memory leaks
Galgo.disable(this);
}
}
其实就是一个Service上面显示了一个window Menifest中需要有权限
改造了一下代码,
1.把Service做成一个全局的, 而不是bind到唯一的Activity , 这才是全局的Log
2.把GalgoOptions 放到了Galgo.java中
/*
* Copyright (C) 2014 Inaka.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Henrique Boregio (henrique@inakanetworks.com)
*/
package com.kookong.tv.debug;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import com.hzy.tvmao.TmApp;
public class Galgo
{
private static final Handler UI_HANDLER = new Handler(Looper.getMainLooper())
{
@Override
public void handleMessage(Message msg) {
if (!isServiceRunning) {//service 停止了就不要往service发消息了
return;
}
String message = (String) msg.obj;
Intent intent = new Intent(TmApp.getContext(), GalgoService.class);
intent.putExtra(MESSAGE, message);
TmApp.getContext().startService(intent);
}
};
public static final String MESSAGE = "galgo.message";
public static final String ARG_OPTIONS = "galgo.options";
private static final String TAG = "Galgo";
private static GalgoOptions sOptions;
private static Context sContext;
private static boolean isServiceRunning;
/**
* * Starts a new Galgo with custom {@link com.inaka.galgo.GalgoOptions}
*
* @param context
* Context
* @param options
* Custom {@link com.inaka.galgo.GalgoOptions}
*/
public static void enable(GalgoOptions options) {
sOptions = options;
init();
}
/**
* Starts a new Galgo with default {@link com.inaka.galgo.GalgoOptions}
*
* @param context
* Context
*/
public static void enable() {
enable(new GalgoOptions.Builder().build());
}
private static void init() {
sContext = TmApp.getContext();
checkPermission(sContext);
// start a new service with our options
Intent intent = new Intent(sContext, GalgoService.class);
intent.putExtra(ARG_OPTIONS, sOptions);
TmApp.getContext().startService(intent);
isServiceRunning = true;
}
public static void disable() {
Intent intent = new Intent(sContext, GalgoService.class);
sContext.stopService(intent);
sContext = null;
isServiceRunning = false;
}
/**
* Logs a String message to the screen. This String will be overlayed on top
* of the UI elements currently displayed on screen. As a side effect, this
* message will also be logged to the standard output via
* {@link android.util.Log}.
*
* @param message
* String to be displayed
*/
public static void log(String message) {
Log.i(TAG, message);
Message msg = UI_HANDLER.obtainMessage(0, message);
msg.sendToTarget();
}
private static void checkPermission(Context context) {
String permission = "android.permission.SYSTEM_ALERT_WINDOW";
int status = context.checkCallingOrSelfPermission(permission);
if (status == PackageManager.PERMISSION_DENIED) {
throw new IllegalStateException("in order to use Galgo, " + "please add the permission " + permission + " to your AndroidManifest.xml");
}
}
public static final class GalgoOptions implements Parcelable
{
public final int numberOfLines;
public final int backgroundColor;
public final int textColor;
public final int textSize;
/**
* Contains options for Galgo. Defines
*
* @param builder
*/
private GalgoOptions(Builder builder) {
numberOfLines = builder.numberOfLines;
backgroundColor = builder.backgroundColor;
textColor = builder.textColor;
textSize = builder.textSize;
}
/**
* Builder for {@link com.inaka.galgo.GalgoOptions}
*/
public static class Builder
{
private int numberOfLines = 10;
private int backgroundColor = 0xD993d2b9;
private int textColor = 0xFFFFFFFF;
private int textSize = 10;
/**
*
* @param n
* number of lines
* @return
*/
public Builder numberOfLines(int n) {
ensurePositiveInt(n, "number of lines must be > 0");
numberOfLines = n;
return this;
}
/**
* Sets the background color of the log messages
*
* @param color
* @return
*/
public Builder backgroundColor(int color) {
backgroundColor = color;
return this;
}
/**
* Sets the text color of the log messages
*
* @param color
* @return
*/
public Builder textColor(int color) {
textColor = color;
return this;
}
/**
* Sets the text size of the messages
*
* @param size
* @return
*/
public Builder textSize(int size) {
ensurePositiveInt(size, "text size must be > 0");
textSize = size;
return this;
}
/**
* Creates a {@link com.inaka.galgo.GalgoOptions} with the
* customized parameters
*
* @return
*/
public GalgoOptions build() {
return new GalgoOptions(this);
}
}
private static void ensurePositiveInt(int value, String msg) {
if (value <= 0) {
throw new IllegalArgumentException(msg);
}
}
// Parcelable implementation
private GalgoOptions(Parcel source) {
numberOfLines = source.readInt();
backgroundColor = source.readInt();
textColor = source.readInt();
textSize = source.readInt();
}
public static final Creator CREATOR = new Creator()
{
@Override
public GalgoOptions createFromParcel(Parcel source) {
return new GalgoOptions(source);
}
@Override
public GalgoOptions[] newArray(int size) {
return new GalgoOptions[size];
}
};
@Override
public int describeContents() {
return 0; // No special content.
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeInt(numberOfLines);
dest.writeInt(backgroundColor);
dest.writeInt(textColor);
dest.writeInt(textSize);
}
}
}
/*
* Copyright (C) 2014 Inaka.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* @author Henrique Boregio (henrique@inakanetworks.com)
*/
package com.kookong.tv.debug;
import java.util.ArrayDeque;
import java.util.Collection;
import java.util.Queue;
import android.app.Service;
import android.content.Intent;
import android.graphics.PixelFormat;
import android.os.Binder;
import android.os.IBinder;
import android.text.Spannable;
import android.text.SpannableString;
import android.text.TextUtils;
import android.text.style.BackgroundColorSpan;
import android.view.Gravity;
import android.view.WindowManager;
import android.widget.TextView;
import com.hzy.tvmao.utils.LogUtil;
import com.hzy.tvmao.utils.SystemUtil;
import com.kookong.tv.debug.Galgo.GalgoOptions;
public class GalgoService extends Service
{
private TextView mTextView;
private GalgoOptions mOptions;
private final Queue mLines = new ArrayDeque<>();
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtil.d("onStartCommand");
//首次创建有options
GalgoOptions options = intent.getExtras().getParcelable(Galgo.ARG_OPTIONS);
if (options != null) {
mOptions = options;
}
//显示log的时候有Message
String message = intent.getExtras().getString(Galgo.MESSAGE);
if (!TextUtils.isEmpty(message)) {
displayText(message);
}
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
super.onCreate();
mTextView = new TextView(this);
WindowManager.LayoutParams params = new WindowManager.LayoutParams(WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.TYPE_SYSTEM_OVERLAY, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE, PixelFormat.TRANSLUCENT);
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.addView(mTextView, params);
}
public void displayText(String text) {
mLines.add(text);
if (mLines.size() > mOptions.numberOfLines) {
mLines.poll();
}
redraw(mLines);
}
private void redraw(Collection texts) {
mTextView.setTextSize(mOptions.textSize);
mTextView.setTextColor(mOptions.textColor);
mTextView.setPadding(SystemUtil.getScreenWH()[0] / 4, 0, 0, 0);
Spannable spannable = new SpannableString(TextUtils.join("\n", texts));
spannable.setSpan(new BackgroundColorSpan(mOptions.backgroundColor), 0, spannable.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
mTextView.setText(spannable);
}
@Override
public void onDestroy() {
super.onDestroy();
if (mTextView != null) {
WindowManager wm = (WindowManager) getSystemService(WINDOW_SERVICE);
wm.removeView(mTextView);
}
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
另一个开源项目, 显示所有日志
https://github.com/jgilfelt/GhostLog