package view_inspector.profile;
import android.database.sqlite.SQLiteOpenHelper;
import android.view.View;
import android.view.ViewDebug;
import com.f2prateek.rx.preferences.Preference;
import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.LinkedList;
import java.util.Queue;
import javax.inject.Inject;
import view_inspector.ViewInspector;
import view_inspector.dagger.qualifier.Profiling;
import view_inspector.dagger.scope.PerActivity;
import view_inspector.database.ViewProfile;
@PerActivity public final class ProfileUtil {
@Inject SQLiteOpenHelper db;
@Inject @Profiling Preference<Boolean> profiling;
@Inject public ProfileUtil() {
}
public interface ProfileResultListener {
void onProfileDone();
void onProgress(int step);
}
public void profile(final int samples, final ProfileResultListener listener) {
new Thread(new Runnable() {
@SuppressWarnings("TryWithIdenticalCatches") @Override public void run() {
profiling.set(true);
for (int i = 0; i < samples; i++) {
ByteArrayOutputStream outputStream = null;
try {
final Method dumpMethod =
ViewDebug.class.getDeclaredMethod("dump", View.class, boolean.class, boolean.class,
OutputStream.class);
dumpMethod.setAccessible(true);
final Method profileMethod =
ViewDebug.class.getDeclaredMethod("profile", View.class, OutputStream.class,
String.class);
profileMethod.setAccessible(true);
View viewRootView = ViewInspector.viewRoot.getRootView();
String parameter = viewRootView.getClass().getName() + "@" + Integer.toHexString(
viewRootView.hashCode());
outputStream = new ByteArrayOutputStream();
dumpMethod.invoke(null, viewRootView, false, false, outputStream);
profileMethod.invoke(null, viewRootView, outputStream, parameter);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} finally {
if (outputStream != null) {
String[] strings = outputStream.toString().split("\\n");
Queue<String> hashcodeQueue = new LinkedList<>();
boolean hashcodeStored = false;
for (String str : strings) {
if (!hashcodeStored && !str.equals("DONE.")) {
// store the hashcodes
hashcodeQueue.add(str.split("@")[1].replaceAll("\\s", ""));
} else {
hashcodeStored = true;
if (!str.equals("DONE.")) {
// store the profiles
String[] profiles = str.split(" ");
db.getWritableDatabase()
.insert(ViewProfile.TABLE, null,
new ViewProfile.Builder().viewHashcode(hashcodeQueue.poll())
.measureDuration(Long.parseLong(profiles[0]) / 1000.0)
.layoutDuration(Long.parseLong(profiles[1]) / 1000.0)
.drawDuration(Long.parseLong(profiles[2]) / 1000.0)
.build());
}
}
}
}
}
listener.onProgress(i);
}
profiling.set(false);
listener.onProfileDone();
}
}).start();
}
}