Created
March 7, 2020 19:40
-
-
Save alexjlockwood/3857233659e9981632bab64f84ff282f to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.instabug.library.instacapture.screenshot; | |
import android.annotation.TargetApi; | |
import android.app.Activity; | |
import android.graphics.Bitmap; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.graphics.PorterDuffXfermode; | |
import android.graphics.Rect; | |
import android.graphics.Bitmap.Config; | |
import android.graphics.PorterDuff.Mode; | |
import android.opengl.GLSurfaceView; | |
import android.os.Build.VERSION; | |
import android.util.Pair; | |
import android.view.TextureView; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.webkit.WebView; | |
import androidx.annotation.IdRes; | |
import androidx.annotation.Nullable; | |
import com.instabug.library.Instabug; | |
import com.instabug.library.instacapture.c.a; | |
import com.instabug.library.settings.SettingsManager; | |
import com.instabug.library.util.DisplayUtils; | |
import com.instabug.library.util.InstabugSDKLogger; | |
import io.reactivex.Observable; | |
import io.reactivex.ObservableEmitter; | |
import io.reactivex.ObservableOnSubscribe; | |
import io.reactivex.ObservableSource; | |
import io.reactivex.android.schedulers.AndroidSchedulers; | |
import io.reactivex.functions.Function; | |
import io.reactivex.schedulers.Schedulers; | |
import java.lang.ref.WeakReference; | |
import java.nio.IntBuffer; | |
import java.util.ArrayList; | |
import java.util.Collection; | |
import java.util.HashMap; | |
import java.util.HashSet; | |
import java.util.Iterator; | |
import java.util.List; | |
import java.util.Map.Entry; | |
import java.util.concurrent.CountDownLatch; | |
import javax.microedition.khronos.egl.EGL10; | |
import javax.microedition.khronos.egl.EGLContext; | |
import javax.microedition.khronos.opengles.GL10; | |
public final class ScreenshotTaker { | |
private ScreenshotTaker() { | |
} | |
public static Observable<Bitmap> getScreenshotBitmap(Activity activity, @Nullable @IdRes int[] ignoredViewsIds) { | |
if (activity == null) { | |
throw new IllegalArgumentException("Parameter activity cannot be null."); | |
} else { | |
View var2 = activity.getWindow().getDecorView(); | |
List var3 = FieldHelper.getRootViews(activity, ignoredViewsIds); | |
InstabugSDKLogger.d(ScreenshotTaker.class, "viewRoots count: " + var3.size()); | |
Bitmap var4; | |
try { | |
if ((long)(var2.getWidth() * var2.getHeight() * 4) < a.a(activity)) { | |
var4 = Bitmap.createBitmap(var2.getWidth(), var2.getHeight(), Config.ARGB_8888); | |
} else { | |
var4 = Bitmap.createBitmap(var2.getWidth(), var2.getHeight(), Config.RGB_565); | |
} | |
} catch (OutOfMemoryError | IllegalArgumentException var6) { | |
return null; | |
} | |
return drawRootsToBitmap(var3, var4, ignoredViewsIds); | |
} | |
} | |
private static Observable<Bitmap> drawRootsToBitmap(List<RootViewInfo> viewRoots, final Bitmap bitmap, @Nullable @IdRes final int[] ignoredViewsIds) { | |
return Observable.fromIterable(viewRoots).flatMap(new Function<RootViewInfo, ObservableSource<Bitmap>>() { | |
public ObservableSource<Bitmap> a(RootViewInfo var1) throws Exception { | |
return ScreenshotTaker.drawRootToBitmap(var1, bitmap, ignoredViewsIds); | |
} | |
}); | |
} | |
private static Observable<Bitmap> drawRootToBitmap(final RootViewInfo rootViewInfo, final Bitmap bitmap, @Nullable @IdRes final int[] ignoredViewsIds) { | |
return Observable.create(new ObservableOnSubscribe<Pair<Canvas, HashMap<View, Integer>>>() { | |
public void subscribe(ObservableEmitter<Pair<Canvas, HashMap<View, Integer>>> emitter) throws Exception { | |
Canvas var2; | |
if ((rootViewInfo.getLayoutParams().flags & 2) == 2) { | |
var2 = new Canvas(bitmap); | |
int var3 = (int)(255.0F * rootViewInfo.getLayoutParams().dimAmount); | |
var2.drawARGB(var3, 0, 0, 0); | |
} | |
var2 = new Canvas(bitmap); | |
var2.translate((float)rootViewInfo.getLeft(), (float)rootViewInfo.getTop()); | |
HashMap var6 = new HashMap(); | |
if (ignoredViewsIds != null) { | |
for(int var4 = 0; var4 < ignoredViewsIds.length; ++var4) { | |
View var5 = rootViewInfo.getView().findViewById(ignoredViewsIds[var4]); | |
if (var5 != null) { | |
var6.put(var5, var5.getVisibility()); | |
} | |
} | |
} | |
emitter.onNext(new Pair(var2, var6)); | |
} | |
}).subscribeOn(Schedulers.single()).observeOn(AndroidSchedulers.mainThread()).map(new Function<Pair<Canvas, HashMap<View, Integer>>, Pair<Canvas, HashMap<View, Integer>>>() { | |
public Pair<Canvas, HashMap<View, Integer>> a(Pair<Canvas, HashMap<View, Integer>> var1) throws Exception { | |
Iterator var2 = ((HashMap)var1.second).keySet().iterator(); | |
while(var2.hasNext()) { | |
View var3 = (View)var2.next(); | |
var3.setVisibility(4); | |
} | |
rootViewInfo.getView().draw((Canvas)var1.first); | |
return var1; | |
} | |
}).observeOn(Schedulers.single()).map(new Function<Pair<Canvas, HashMap<View, Integer>>, HashMap<View, Integer>>() { | |
public HashMap<View, Integer> a(Pair<Canvas, HashMap<View, Integer>> var1) throws Exception { | |
ScreenshotTaker.drawUnDrawableViews(rootViewInfo.getView(), (Canvas)var1.first); | |
Collection var2 = SettingsManager.getInstance().getPrivateViews(); | |
HashSet var3 = new HashSet(); | |
Iterator var4 = var2.iterator(); | |
while(true) { | |
while(var4.hasNext()) { | |
WeakReference var5 = (WeakReference)var4.next(); | |
if (var5 != null && var5.get() != null) { | |
View var6 = (View)var5.get(); | |
if (var6 != null && ScreenshotTaker.isVisible(var6)) { | |
int[] var7 = new int[2]; | |
var6.getLocationOnScreen(var7); | |
((Canvas)var1.first).drawRect(ScreenshotTaker.getVisibleRect(var6), new Paint()); | |
} | |
} else { | |
var3.add(var5); | |
} | |
} | |
SettingsManager.getInstance().getPrivateViews().removeAll(var3); | |
return (HashMap)var1.second; | |
} | |
} | |
}).observeOn(AndroidSchedulers.mainThread()).map(new Function<HashMap<View, Integer>, Bitmap>() { | |
public Bitmap a(HashMap<View, Integer> var1) throws Exception { | |
Iterator var2 = var1.entrySet().iterator(); | |
while(var2.hasNext()) { | |
Entry var3 = (Entry)var2.next(); | |
((View)var3.getKey()).setVisibility((Integer)var3.getValue()); | |
} | |
return bitmap; | |
} | |
}); | |
} | |
public static boolean isVisible(View view) { | |
if (!view.isShown()) { | |
return false; | |
} else { | |
Rect var1 = new Rect(); | |
view.getGlobalVisibleRect(var1); | |
Rect var2 = new Rect(0, 0, DisplayUtils.getDisplayWidthInPx(Instabug.getApplicationContext()), DisplayUtils.getDisplayHeightInPx(Instabug.getApplicationContext())); | |
return var1.intersect(var2); | |
} | |
} | |
private static Rect getVisibleRect(@Nullable View childView) { | |
Rect var1 = new Rect(); | |
if (childView != null && childView.getVisibility() == 0 && childView.getRootView().getParent() != null) { | |
return !childView.getGlobalVisibleRect(var1) ? new Rect(0, 0, 0, 0) : var1; | |
} else { | |
return new Rect(0, 0, 0, 0); | |
} | |
} | |
private static ArrayList<View> drawUnDrawableViews(View v, Canvas canvas) { | |
ArrayList var2; | |
if (!(v instanceof ViewGroup)) { | |
var2 = new ArrayList(); | |
var2.add(v); | |
return var2; | |
} else { | |
var2 = new ArrayList(); | |
ViewGroup var3 = (ViewGroup)v; | |
for(int var4 = 0; var4 < var3.getChildCount(); ++var4) { | |
View var5 = var3.getChildAt(var4); | |
ArrayList var6 = new ArrayList(); | |
var6.add(v); | |
var6.addAll(drawUnDrawableViews(var5, canvas)); | |
int[] var7 = new int[2]; | |
var5.getLocationOnScreen(var7); | |
if (VERSION.SDK_INT >= 14 && var5 instanceof TextureView) { | |
drawTextureView((TextureView)var5, var7, canvas); | |
} | |
if (var5 instanceof GLSurfaceView) { | |
drawGLSurfaceView((GLSurfaceView)var5, var7, canvas); | |
} | |
if (VERSION.SDK_INT >= 11 && var5 instanceof WebView) { | |
drawWebView((WebView)var5, canvas); | |
} | |
var2.addAll(var6); | |
} | |
return var2; | |
} | |
} | |
public static void drawGLSurfaceView(GLSurfaceView surfaceView, int[] locationOnScreen, Canvas canvas) { | |
InstabugSDKLogger.d(ScreenshotTaker.class, "Drawing GLSurfaceView"); | |
if (surfaceView.getWindowToken() != null) { | |
final int var3 = surfaceView.getWidth(); | |
final int var4 = surfaceView.getHeight(); | |
boolean var5 = false; | |
boolean var6 = false; | |
int[] var7 = new int[var3 * (0 + var4)]; | |
final IntBuffer var8 = IntBuffer.wrap(var7); | |
var8.position(0); | |
final CountDownLatch var9 = new CountDownLatch(1); | |
surfaceView.queueEvent(new Runnable() { | |
public void run() { | |
EGL10 var1 = (EGL10)EGLContext.getEGL(); | |
var1.eglWaitGL(); | |
GL10 var2 = (GL10)var1.eglGetCurrentContext().getGL(); | |
var2.glFinish(); | |
try { | |
Thread.sleep(200L); | |
} catch (InterruptedException var4x) { | |
var4x.printStackTrace(); | |
} | |
var2.glReadPixels(0, 0, var3, 0 + var4, 6408, 5121, var8); | |
var9.countDown(); | |
} | |
}); | |
try { | |
var9.await(); | |
} catch (InterruptedException var18) { | |
var18.printStackTrace(); | |
} | |
int[] var10 = new int[var3 * var4]; | |
int var11 = 0; | |
for(int var12 = 0; var11 < var4; ++var12) { | |
for(int var13 = 0; var13 < var3; ++var13) { | |
int var14 = var7[var11 * var3 + var13]; | |
int var15 = var14 >> 16 & 255; | |
int var16 = var14 << 16 & 16711680; | |
int var17 = var14 & -16711936 | var16 | var15; | |
var10[(var4 - var12 - 1) * var3 + var13] = var17; | |
} | |
++var11; | |
} | |
Bitmap var19 = Bitmap.createBitmap(var10, var3, var4, Config.ARGB_8888); | |
Paint var20 = new Paint(); | |
var20.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP)); | |
canvas.drawBitmap(var19, (float)locationOnScreen[0], (float)locationOnScreen[1], var20); | |
var19.recycle(); | |
} | |
} | |
@TargetApi(14) | |
public static void drawTextureView(TextureView textureView, int[] locationOnScreen, Canvas canvas) { | |
InstabugSDKLogger.d(ScreenshotTaker.class, "Drawing TextureView"); | |
try { | |
Bitmap var3 = textureView.getBitmap(); | |
if (var3 != null) { | |
Paint var4 = new Paint(); | |
var4.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP)); | |
canvas.drawBitmap(var3, (float)locationOnScreen[0], (float)locationOnScreen[1], var4); | |
var3.recycle(); | |
} | |
} catch (OutOfMemoryError var5) { | |
InstabugSDKLogger.e(ScreenshotTaker.class, ScreenshotTaker.class.getSimpleName(), var5); | |
} | |
} | |
@TargetApi(11) | |
public static void drawWebView(WebView webView, Canvas canvas) { | |
int var2 = webView.getLayerType(); | |
if (var2 == 2) { | |
webView.setLayerType(0, (Paint)null); | |
webView.setDrawingCacheEnabled(true); | |
webView.buildDrawingCache(true); | |
Bitmap var3 = webView.getDrawingCache(); | |
if (var3 != null) { | |
Paint var4 = new Paint(); | |
var4.setXfermode(new PorterDuffXfermode(Mode.DST_ATOP)); | |
int[] var5 = new int[2]; | |
webView.getLocationOnScreen(var5); | |
canvas.drawBitmap(var3, (float)var5[0], (float)var5[1], var4); | |
var3.recycle(); | |
} | |
webView.setDrawingCacheEnabled(false); | |
webView.setLayerType(var2, (Paint)null); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment