Rabbit-R1/android (non root)/java/sources/org/webrtc/EglRenderer.java
2024-05-21 17:08:36 -04:00

682 lines
28 KiB
Java

package org.webrtc;
import android.graphics.Bitmap;
import android.graphics.Matrix;
import android.graphics.SurfaceTexture;
import android.opengl.GLES20;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.Message;
import android.view.Surface;
import java.nio.ByteBuffer;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.webrtc.EglBase;
import org.webrtc.GlUtil;
import org.webrtc.RendererCommon;
/* loaded from: classes3.dex */
public class EglRenderer implements VideoSink {
private static final long LOG_INTERVAL_SEC = 4;
private static final String TAG = "EglRenderer";
private final GlTextureFrameBuffer bitmapTextureFramebuffer;
private final Matrix drawMatrix;
private RendererCommon.GlDrawer drawer;
private EglBase eglBase;
private final EglSurfaceCreation eglSurfaceCreationRunnable;
private volatile ErrorCallback errorCallback;
private final Object fpsReductionLock;
private final VideoFrameDrawer frameDrawer;
private final ArrayList<FrameListenerAndParams> frameListeners;
private final Object frameLock;
private int framesDropped;
private int framesReceived;
private int framesRendered;
private final Object handlerLock;
private float layoutAspectRatio;
private final Object layoutLock;
private final Runnable logStatisticsRunnable;
private long minRenderPeriodNs;
private boolean mirrorHorizontally;
private boolean mirrorVertically;
protected final String name;
private long nextFrameTimeNs;
private VideoFrame pendingFrame;
private long renderSwapBufferTimeNs;
private Handler renderThreadHandler;
private long renderTimeNs;
private final Object statisticsLock;
private long statisticsStartTimeNs;
private boolean usePresentationTimeStamp;
/* loaded from: classes3.dex */
public interface ErrorCallback {
void onGlOutOfMemory();
}
/* loaded from: classes3.dex */
public interface FrameListener {
void onFrame(Bitmap bitmap);
}
public void setErrorCallback(ErrorCallback errorCallback) {
this.errorCallback = errorCallback;
}
/* JADX INFO: Access modifiers changed from: private */
/* loaded from: classes3.dex */
public static class FrameListenerAndParams {
public final boolean applyFpsReduction;
public final RendererCommon.GlDrawer drawer;
public final FrameListener listener;
public final float scale;
public FrameListenerAndParams(FrameListener frameListener, float f, RendererCommon.GlDrawer glDrawer, boolean z) {
this.listener = frameListener;
this.scale = f;
this.drawer = glDrawer;
this.applyFpsReduction = z;
}
}
/* JADX INFO: Access modifiers changed from: private */
/* loaded from: classes3.dex */
public class EglSurfaceCreation implements Runnable {
private Object surface;
private EglSurfaceCreation() {
}
public synchronized void setSurface(Object obj) {
this.surface = obj;
}
@Override // java.lang.Runnable
public synchronized void run() {
if (this.surface != null && EglRenderer.this.eglBase != null && !EglRenderer.this.eglBase.hasSurface()) {
Object obj = this.surface;
if (obj instanceof Surface) {
EglRenderer.this.eglBase.createSurface((Surface) this.surface);
} else if (obj instanceof SurfaceTexture) {
EglRenderer.this.eglBase.createSurface((SurfaceTexture) this.surface);
} else {
throw new IllegalStateException("Invalid surface: " + this.surface);
}
EglRenderer.this.eglBase.makeCurrent();
GLES20.glPixelStorei(3317, 1);
}
}
}
/* JADX INFO: Access modifiers changed from: private */
/* loaded from: classes3.dex */
public static class HandlerWithExceptionCallback extends Handler {
private final Runnable exceptionCallback;
public HandlerWithExceptionCallback(Looper looper, Runnable runnable) {
super(looper);
this.exceptionCallback = runnable;
}
@Override // android.os.Handler
public void dispatchMessage(Message message) {
try {
super.dispatchMessage(message);
} catch (Exception e) {
Logging.e(EglRenderer.TAG, "Exception on EglRenderer thread", e);
this.exceptionCallback.run();
throw e;
}
}
}
public EglRenderer(String str) {
this(str, new VideoFrameDrawer());
}
public EglRenderer(String str, VideoFrameDrawer videoFrameDrawer) {
this.handlerLock = new Object();
this.frameListeners = new ArrayList<>();
this.fpsReductionLock = new Object();
this.drawMatrix = new Matrix();
this.frameLock = new Object();
this.layoutLock = new Object();
this.statisticsLock = new Object();
this.bitmapTextureFramebuffer = new GlTextureFrameBuffer(6408);
this.logStatisticsRunnable = new Runnable() { // from class: org.webrtc.EglRenderer.1
@Override // java.lang.Runnable
public void run() {
EglRenderer.this.logStatistics();
synchronized (EglRenderer.this.handlerLock) {
if (EglRenderer.this.renderThreadHandler != null) {
EglRenderer.this.renderThreadHandler.removeCallbacks(EglRenderer.this.logStatisticsRunnable);
EglRenderer.this.renderThreadHandler.postDelayed(EglRenderer.this.logStatisticsRunnable, TimeUnit.SECONDS.toMillis(EglRenderer.LOG_INTERVAL_SEC));
}
}
}
};
this.eglSurfaceCreationRunnable = new EglSurfaceCreation();
this.name = str;
this.frameDrawer = videoFrameDrawer;
}
public void init(final EglBase.Context context, final int[] iArr, RendererCommon.GlDrawer glDrawer, boolean z) {
synchronized (this.handlerLock) {
if (this.renderThreadHandler != null) {
throw new IllegalStateException(this.name + "Already initialized");
}
logD("Initializing EglRenderer");
this.drawer = glDrawer;
this.usePresentationTimeStamp = z;
HandlerThread handlerThread = new HandlerThread(this.name + TAG);
handlerThread.start();
HandlerWithExceptionCallback handlerWithExceptionCallback = new HandlerWithExceptionCallback(handlerThread.getLooper(), new Runnable() { // from class: org.webrtc.EglRenderer.2
@Override // java.lang.Runnable
public void run() {
synchronized (EglRenderer.this.handlerLock) {
EglRenderer.this.renderThreadHandler = null;
}
}
});
this.renderThreadHandler = handlerWithExceptionCallback;
ThreadUtils.invokeAtFrontUninterruptibly(handlerWithExceptionCallback, new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda7
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.m7432lambda$init$0$orgwebrtcEglRenderer(context, iArr);
}
});
this.renderThreadHandler.post(this.eglSurfaceCreationRunnable);
resetStatistics(System.nanoTime());
this.renderThreadHandler.postDelayed(this.logStatisticsRunnable, TimeUnit.SECONDS.toMillis(LOG_INTERVAL_SEC));
}
}
/* JADX INFO: Access modifiers changed from: package-private */
/* renamed from: lambda$init$0$org-webrtc-EglRenderer, reason: not valid java name */
public /* synthetic */ void m7432lambda$init$0$orgwebrtcEglRenderer(EglBase.Context context, int[] iArr) {
if (context == null) {
logD("EglBase10.create context");
this.eglBase = EglBase.createEgl10(iArr);
} else {
logD("EglBase.create shared context");
this.eglBase = EglBase.create(context, iArr);
}
}
public void init(EglBase.Context context, int[] iArr, RendererCommon.GlDrawer glDrawer) {
init(context, iArr, glDrawer, false);
}
public void createEglSurface(Surface surface) {
createEglSurfaceInternal(surface);
}
public void createEglSurface(SurfaceTexture surfaceTexture) {
createEglSurfaceInternal(surfaceTexture);
}
private void createEglSurfaceInternal(Object obj) {
this.eglSurfaceCreationRunnable.setSurface(obj);
postToRenderThread(this.eglSurfaceCreationRunnable);
}
public void release() {
logD("Releasing.");
final CountDownLatch countDownLatch = new CountDownLatch(1);
synchronized (this.handlerLock) {
Handler handler = this.renderThreadHandler;
if (handler == null) {
logD("Already released");
return;
}
handler.removeCallbacks(this.logStatisticsRunnable);
this.renderThreadHandler.postAtFrontOfQueue(new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda2
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.m7433lambda$release$1$orgwebrtcEglRenderer(countDownLatch);
}
});
final Looper looper = this.renderThreadHandler.getLooper();
this.renderThreadHandler.post(new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda3
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.m7434lambda$release$2$orgwebrtcEglRenderer(looper);
}
});
this.renderThreadHandler = null;
ThreadUtils.awaitUninterruptibly(countDownLatch);
synchronized (this.frameLock) {
VideoFrame videoFrame = this.pendingFrame;
if (videoFrame != null) {
videoFrame.release();
this.pendingFrame = null;
}
}
logD("Releasing done.");
}
}
/* JADX INFO: Access modifiers changed from: package-private */
/* renamed from: lambda$release$1$org-webrtc-EglRenderer, reason: not valid java name */
public /* synthetic */ void m7433lambda$release$1$orgwebrtcEglRenderer(CountDownLatch countDownLatch) {
synchronized (EglBase.lock) {
GLES20.glUseProgram(0);
}
RendererCommon.GlDrawer glDrawer = this.drawer;
if (glDrawer != null) {
glDrawer.release();
this.drawer = null;
}
this.frameDrawer.release();
this.bitmapTextureFramebuffer.release();
if (this.eglBase != null) {
logD("eglBase detach and release.");
this.eglBase.detachCurrent();
this.eglBase.release();
this.eglBase = null;
}
this.frameListeners.clear();
countDownLatch.countDown();
}
/* JADX INFO: Access modifiers changed from: package-private */
/* renamed from: lambda$release$2$org-webrtc-EglRenderer, reason: not valid java name */
public /* synthetic */ void m7434lambda$release$2$orgwebrtcEglRenderer(Looper looper) {
logD("Quitting render thread.");
looper.quit();
}
private void resetStatistics(long j) {
synchronized (this.statisticsLock) {
this.statisticsStartTimeNs = j;
this.framesReceived = 0;
this.framesDropped = 0;
this.framesRendered = 0;
this.renderTimeNs = 0L;
this.renderSwapBufferTimeNs = 0L;
}
}
public void printStackTrace() {
synchronized (this.handlerLock) {
Handler handler = this.renderThreadHandler;
Thread thread = handler == null ? null : handler.getLooper().getThread();
if (thread != null) {
StackTraceElement[] stackTrace = thread.getStackTrace();
if (stackTrace.length > 0) {
logW("EglRenderer stack trace:");
for (StackTraceElement stackTraceElement : stackTrace) {
logW(stackTraceElement.toString());
}
}
}
}
}
public void setMirror(boolean z) {
logD("setMirrorHorizontally: " + z);
synchronized (this.layoutLock) {
this.mirrorHorizontally = z;
}
}
public void setMirrorVertically(boolean z) {
logD("setMirrorVertically: " + z);
synchronized (this.layoutLock) {
this.mirrorVertically = z;
}
}
public void setLayoutAspectRatio(float f) {
logD("setLayoutAspectRatio: " + f);
synchronized (this.layoutLock) {
this.layoutAspectRatio = f;
}
}
public void setFpsReduction(float f) {
logD("setFpsReduction: " + f);
synchronized (this.fpsReductionLock) {
long j = this.minRenderPeriodNs;
if (f <= 0.0f) {
this.minRenderPeriodNs = Long.MAX_VALUE;
} else {
this.minRenderPeriodNs = ((float) TimeUnit.SECONDS.toNanos(1L)) / f;
}
if (this.minRenderPeriodNs != j) {
this.nextFrameTimeNs = System.nanoTime();
}
}
}
public void disableFpsReduction() {
setFpsReduction(Float.POSITIVE_INFINITY);
}
public void pauseVideo() {
setFpsReduction(0.0f);
}
public void addFrameListener(FrameListener frameListener, float f) {
addFrameListener(frameListener, f, null, false);
}
public void addFrameListener(FrameListener frameListener, float f, RendererCommon.GlDrawer glDrawer) {
addFrameListener(frameListener, f, glDrawer, false);
}
public void addFrameListener(final FrameListener frameListener, final float f, final RendererCommon.GlDrawer glDrawer, final boolean z) {
postToRenderThread(new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda4
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.m7430lambda$addFrameListener$3$orgwebrtcEglRenderer(glDrawer, frameListener, f, z);
}
});
}
/* JADX INFO: Access modifiers changed from: package-private */
/* renamed from: lambda$addFrameListener$3$org-webrtc-EglRenderer, reason: not valid java name */
public /* synthetic */ void m7430lambda$addFrameListener$3$orgwebrtcEglRenderer(RendererCommon.GlDrawer glDrawer, FrameListener frameListener, float f, boolean z) {
if (glDrawer == null) {
glDrawer = this.drawer;
}
this.frameListeners.add(new FrameListenerAndParams(frameListener, f, glDrawer, z));
}
public void removeFrameListener(final FrameListener frameListener) {
final CountDownLatch countDownLatch = new CountDownLatch(1);
synchronized (this.handlerLock) {
if (this.renderThreadHandler == null) {
return;
}
if (Thread.currentThread() == this.renderThreadHandler.getLooper().getThread()) {
throw new RuntimeException("removeFrameListener must not be called on the render thread.");
}
postToRenderThread(new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda1
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.m7436lambda$removeFrameListener$4$orgwebrtcEglRenderer(countDownLatch, frameListener);
}
});
ThreadUtils.awaitUninterruptibly(countDownLatch);
}
}
/* JADX INFO: Access modifiers changed from: package-private */
/* renamed from: lambda$removeFrameListener$4$org-webrtc-EglRenderer, reason: not valid java name */
public /* synthetic */ void m7436lambda$removeFrameListener$4$orgwebrtcEglRenderer(CountDownLatch countDownLatch, FrameListener frameListener) {
countDownLatch.countDown();
Iterator<FrameListenerAndParams> it = this.frameListeners.iterator();
while (it.hasNext()) {
if (it.next().listener == frameListener) {
it.remove();
}
}
}
@Override // org.webrtc.VideoSink
public void onFrame(VideoFrame videoFrame) {
boolean z;
synchronized (this.statisticsLock) {
this.framesReceived++;
}
synchronized (this.handlerLock) {
if (this.renderThreadHandler == null) {
logD("Dropping frame - Not initialized or already released.");
return;
}
synchronized (this.frameLock) {
VideoFrame videoFrame2 = this.pendingFrame;
z = videoFrame2 != null;
if (z) {
videoFrame2.release();
}
this.pendingFrame = videoFrame;
videoFrame.retain();
this.renderThreadHandler.post(new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda0
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.renderFrameOnRenderThread();
}
});
}
if (z) {
synchronized (this.statisticsLock) {
this.framesDropped++;
}
}
}
}
public void releaseEglSurface(final Runnable runnable) {
this.eglSurfaceCreationRunnable.setSurface(null);
synchronized (this.handlerLock) {
Handler handler = this.renderThreadHandler;
if (handler != null) {
handler.removeCallbacks(this.eglSurfaceCreationRunnable);
this.renderThreadHandler.postAtFrontOfQueue(new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda5
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.m7435lambda$releaseEglSurface$5$orgwebrtcEglRenderer(runnable);
}
});
} else {
runnable.run();
}
}
}
/* JADX INFO: Access modifiers changed from: package-private */
/* renamed from: lambda$releaseEglSurface$5$org-webrtc-EglRenderer, reason: not valid java name */
public /* synthetic */ void m7435lambda$releaseEglSurface$5$orgwebrtcEglRenderer(Runnable runnable) {
EglBase eglBase = this.eglBase;
if (eglBase != null) {
eglBase.detachCurrent();
this.eglBase.releaseSurface();
}
runnable.run();
}
private void postToRenderThread(Runnable runnable) {
synchronized (this.handlerLock) {
Handler handler = this.renderThreadHandler;
if (handler != null) {
handler.post(runnable);
}
}
}
/* JADX INFO: Access modifiers changed from: private */
/* renamed from: clearSurfaceOnRenderThread, reason: merged with bridge method [inline-methods] */
public void m7431lambda$clearImage$6$orgwebrtcEglRenderer(float f, float f2, float f3, float f4) {
EglBase eglBase = this.eglBase;
if (eglBase == null || !eglBase.hasSurface()) {
return;
}
logD("clearSurface");
GLES20.glClearColor(f, f2, f3, f4);
GLES20.glClear(16384);
this.eglBase.swapBuffers();
}
public void clearImage() {
clearImage(0.0f, 0.0f, 0.0f, 0.0f);
}
public void clearImage(final float f, final float f2, final float f3, final float f4) {
synchronized (this.handlerLock) {
Handler handler = this.renderThreadHandler;
if (handler == null) {
return;
}
handler.postAtFrontOfQueue(new Runnable() { // from class: org.webrtc.EglRenderer$$ExternalSyntheticLambda6
@Override // java.lang.Runnable
public final void run() {
EglRenderer.this.m7431lambda$clearImage$6$orgwebrtcEglRenderer(f, f2, f3, f4);
}
});
}
}
/* JADX INFO: Access modifiers changed from: private */
public void renderFrameOnRenderThread() {
boolean z;
float f;
float f2;
float f3;
synchronized (this.frameLock) {
VideoFrame videoFrame = this.pendingFrame;
if (videoFrame == null) {
return;
}
this.pendingFrame = null;
EglBase eglBase = this.eglBase;
if (eglBase == null || !eglBase.hasSurface()) {
logD("Dropping frame - No surface");
return;
}
synchronized (this.fpsReductionLock) {
long j = this.minRenderPeriodNs;
if (j != Long.MAX_VALUE) {
if (j > 0) {
long nanoTime = System.nanoTime();
long j2 = this.nextFrameTimeNs;
if (nanoTime < j2) {
logD("Skipping frame rendering - fps reduction is active.");
} else {
long j3 = j2 + this.minRenderPeriodNs;
this.nextFrameTimeNs = j3;
this.nextFrameTimeNs = Math.max(j3, nanoTime);
}
}
z = true;
}
z = false;
}
long nanoTime2 = System.nanoTime();
float rotatedWidth = videoFrame.getRotatedWidth() / videoFrame.getRotatedHeight();
synchronized (this.layoutLock) {
f = this.layoutAspectRatio;
if (f == 0.0f) {
f = rotatedWidth;
}
}
if (rotatedWidth > f) {
f3 = f / rotatedWidth;
f2 = 1.0f;
} else {
f2 = rotatedWidth / f;
f3 = 1.0f;
}
this.drawMatrix.reset();
this.drawMatrix.preTranslate(0.5f, 0.5f);
this.drawMatrix.preScale(this.mirrorHorizontally ? -1.0f : 1.0f, this.mirrorVertically ? -1.0f : 1.0f);
this.drawMatrix.preScale(f3, f2);
this.drawMatrix.preTranslate(-0.5f, -0.5f);
try {
if (z) {
try {
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.glClear(16384);
this.frameDrawer.drawFrame(videoFrame, this.drawer, this.drawMatrix, 0, 0, this.eglBase.surfaceWidth(), this.eglBase.surfaceHeight());
long nanoTime3 = System.nanoTime();
if (this.usePresentationTimeStamp) {
this.eglBase.swapBuffers(videoFrame.getTimestampNs());
} else {
this.eglBase.swapBuffers();
}
long nanoTime4 = System.nanoTime();
synchronized (this.statisticsLock) {
this.framesRendered++;
this.renderTimeNs += nanoTime4 - nanoTime2;
this.renderSwapBufferTimeNs += nanoTime4 - nanoTime3;
}
} catch (GlUtil.GlOutOfMemoryException e) {
logE("Error while drawing frame", e);
ErrorCallback errorCallback = this.errorCallback;
if (errorCallback != null) {
errorCallback.onGlOutOfMemory();
}
this.drawer.release();
this.frameDrawer.release();
this.bitmapTextureFramebuffer.release();
}
}
notifyCallbacks(videoFrame, z);
} finally {
videoFrame.release();
}
}
}
private void notifyCallbacks(VideoFrame videoFrame, boolean z) {
if (this.frameListeners.isEmpty()) {
return;
}
this.drawMatrix.reset();
this.drawMatrix.preTranslate(0.5f, 0.5f);
this.drawMatrix.preScale(this.mirrorHorizontally ? -1.0f : 1.0f, this.mirrorVertically ? -1.0f : 1.0f);
this.drawMatrix.preScale(1.0f, -1.0f);
this.drawMatrix.preTranslate(-0.5f, -0.5f);
Iterator<FrameListenerAndParams> it = this.frameListeners.iterator();
while (it.hasNext()) {
FrameListenerAndParams next = it.next();
if (z || !next.applyFpsReduction) {
it.remove();
int rotatedWidth = (int) (next.scale * videoFrame.getRotatedWidth());
int rotatedHeight = (int) (next.scale * videoFrame.getRotatedHeight());
if (rotatedWidth == 0 || rotatedHeight == 0) {
next.listener.onFrame(null);
} else {
this.bitmapTextureFramebuffer.setSize(rotatedWidth, rotatedHeight);
GLES20.glBindFramebuffer(36160, this.bitmapTextureFramebuffer.getFrameBufferId());
GLES20.glFramebufferTexture2D(36160, 36064, 3553, this.bitmapTextureFramebuffer.getTextureId(), 0);
GLES20.glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
GLES20.glClear(16384);
this.frameDrawer.drawFrame(videoFrame, next.drawer, this.drawMatrix, 0, 0, rotatedWidth, rotatedHeight);
ByteBuffer allocateDirect = ByteBuffer.allocateDirect(rotatedWidth * rotatedHeight * 4);
GLES20.glViewport(0, 0, rotatedWidth, rotatedHeight);
GLES20.glReadPixels(0, 0, rotatedWidth, rotatedHeight, 6408, 5121, allocateDirect);
GLES20.glBindFramebuffer(36160, 0);
GlUtil.checkNoGLES2Error("EglRenderer.notifyCallbacks");
Bitmap createBitmap = Bitmap.createBitmap(rotatedWidth, rotatedHeight, Bitmap.Config.ARGB_8888);
createBitmap.copyPixelsFromBuffer(allocateDirect);
next.listener.onFrame(createBitmap);
}
}
}
}
private String averageTimeAsString(long j, int i) {
return i <= 0 ? "NA" : TimeUnit.NANOSECONDS.toMicros(j / i) + " us";
}
/* JADX INFO: Access modifiers changed from: private */
public void logStatistics() {
DecimalFormat decimalFormat = new DecimalFormat("#.0");
long nanoTime = System.nanoTime();
synchronized (this.statisticsLock) {
long j = nanoTime - this.statisticsStartTimeNs;
if (j > 0 && (this.minRenderPeriodNs != Long.MAX_VALUE || this.framesReceived != 0)) {
logD("Duration: " + TimeUnit.NANOSECONDS.toMillis(j) + " ms. Frames received: " + this.framesReceived + ". Dropped: " + this.framesDropped + ". Rendered: " + this.framesRendered + ". Render fps: " + decimalFormat.format(((float) (this.framesRendered * TimeUnit.SECONDS.toNanos(1L))) / ((float) j)) + ". Average render time: " + averageTimeAsString(this.renderTimeNs, this.framesRendered) + ". Average swapBuffer time: " + averageTimeAsString(this.renderSwapBufferTimeNs, this.framesRendered) + ".");
resetStatistics(nanoTime);
}
}
}
private void logE(String str, Throwable th) {
Logging.e(TAG, this.name + str, th);
}
private void logD(String str) {
Logging.d(TAG, this.name + str);
}
private void logW(String str) {
Logging.w(TAG, this.name + str);
}
}