Last active
June 22, 2022 15:08
-
-
Save subtleGradient/ff0cd66816aa4cab881d0e27d900bcd6 to your computer and use it in GitHub Desktop.
This file contains hidden or 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
#!/usr/bin/env bash -l | |
SourceClass="${1:-$PWD/SandyShorts.java}" | |
SourceRoot="$(dirname "$SourceClass")" | |
ClassName="$(basename "$SourceClass" .java)" | |
TimeStamp=$(date -j -f "%a %b %d %T %Z %Y" "`date`" "+%s") | |
FakePackageName="v$TimeStamp" | |
# FakePackageName="$(git hash-object "$SourceClass"|cut -c1-10)_$TimeStamp" | |
DestinationRoot="$PWD/build" | |
DestinationDexFile="$SourceRoot/$ClassName.dex" | |
ClassPath="$ANDROID_HOME/platforms/android-16/android.jar" | |
if [[ -d "$DestinationRoot/$FakePackageName/$ClassName.java" ]]; then | |
exit 0 | |
fi | |
mkdir -p "$DestinationRoot/$FakePackageName" | |
echo "package $FakePackageName;" > "$DestinationRoot/$FakePackageName/$ClassName.java" | |
cat "$SourceClass" >> "$DestinationRoot/$FakePackageName/$ClassName.java" | |
#TODO make javac into a server or something to make it faster | |
javac -classpath "$ClassPath" "$DestinationRoot/$FakePackageName/$ClassName.java" && \ | |
"$ANDROID_HOME/platform-tools/dx" --dex --no-strict --output="$DestinationDexFile" "$DestinationRoot/$FakePackageName"/*.class && \ | |
"$(dirname $0)/push-dex.sh" "$DestinationDexFile" "$FakePackageName/$ClassName" |
This file contains hidden or 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
#!/usr/bin/env bash -l | |
LocalDexFile="$1" | |
ClassName="$2" | |
RemoteDexFile="/sdcard/pushed.dex" | |
# "$ANDROID_HOME/platform-tools/adb" shell am force-stop "com.subtlegradient.android.thinpushclient/com.subtlegradient.android.thinpushclient.RemoteViewActivity" && sleep 1 || exit $? | |
"$ANDROID_HOME/platform-tools/adb" push "$LocalDexFile" "$RemoteDexFile" && \ | |
"$ANDROID_HOME/platform-tools/adb" shell am start "com.subtlegradient.android.thinpushclient/com.subtlegradient.android.thinpushclient.RemoteViewActivity" && \ | |
"$ANDROID_HOME/platform-tools/adb" shell am broadcast \ | |
-a com.subtlegradient.android.thinpushclient.LOAD \ | |
-e class "$ClassName" \ | |
-e apk "$RemoteDexFile" |
This file contains hidden or 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.subtlegradient.android.thinpushclient; | |
import java.io.File; | |
import java.lang.reflect.Method; | |
import android.annotation.TargetApi; | |
import android.app.Activity; | |
import android.content.BroadcastReceiver; | |
import android.content.Context; | |
import android.content.Intent; | |
import android.content.IntentFilter; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.util.Log; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.TextView; | |
import dalvik.system.DexClassLoader; | |
public class RemoteViewActivity extends Activity { | |
private static final String TAG = "HotCode"; | |
private BroadcastReceiver receiver = new BroadcastReceiver() { | |
@Override | |
public void onReceive(Context context, Intent intent) { | |
Log.d(TAG, "received intent"); | |
String className = intent.getStringExtra("class"); | |
String apkPath = intent.getStringExtra("apk"); | |
if (className != null && apkPath != null) | |
load(apkPath, className); | |
else | |
Log.e(TAG, "intent missing 'class' extra"); | |
} | |
}; | |
private String dexOutputDir; | |
private File dir; | |
@Override | |
public void onCreate(Bundle savedInstanceState) { | |
Log.d(TAG, "listening for '" + "HotCode" + "'"); | |
super.onCreate(savedInstanceState); | |
setContentView(new TextView(getApplicationContext()){{setText("HotCode Receiver");}}); | |
dir = getApplicationContext().getDir("dex", 0); | |
dexOutputDir = dir.getAbsolutePath(); | |
registerReceiver(receiver, new IntentFilter("HotCode")); | |
} | |
@Override | |
protected void onPause() { | |
unregisterReceiver(receiver); | |
super.onPause(); | |
} | |
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) | |
void load(String apkPath, String className) { | |
Log.d(TAG, "loading '" + className + "'"); | |
// for (File file : dir.listFiles()) { | |
// Log.d(TAG, file.getAbsolutePath() + " was deleted? " + file.delete()); | |
// } | |
try { | |
DexClassLoader classLoader = new DexClassLoader(apkPath, dexOutputDir, null, getClass().getClassLoader()); | |
try { | |
Class<?> myClass = classLoader.loadClass(className); | |
// myClass.getConstructor().newInstance(); | |
Log.d(TAG, "SUCCESS! loaded '" + className + "'"); | |
Method method = myClass.getMethods()[0]; | |
Log.d(TAG, "about to invoke '" + className + "." + method.getName() + "'"); | |
// method.invoke(null, getApplicationContext()); | |
method.invoke(null, RemoteViewActivity.this); | |
Log.d(TAG, "SUCCESS! '" + className + "." + method.getName() + "'"); | |
} catch (Exception e) { | |
Log.e(TAG, e.toString()); | |
e.printStackTrace(); | |
} | |
} catch (Exception e) { | |
Log.e(TAG, e.toString()); | |
e.printStackTrace(); | |
} | |
} | |
} |
This file contains hidden or 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
import android.app.Activity; | |
import android.content.Context; | |
import android.graphics.Canvas; | |
import android.graphics.Paint; | |
import android.text.TextPaint; | |
import android.text.TextUtils; | |
import android.util.DisplayMetrics; | |
import android.util.Log; | |
import android.view.DragEvent; | |
import android.view.MotionEvent; | |
import android.view.View; | |
import android.widget.TextView; | |
public class Test { | |
static public void augmentRunningActivity(Activity activity) { | |
final Context context = activity.getApplicationContext(); | |
final DisplayMetrics metrics = context.getResources().getDisplayMetrics(); | |
final float scaledDensity = metrics.scaledDensity; | |
Log.d("thinpushclient", "\n\n\n"); | |
Log.d("thinpushclient", Test.class.getName()); | |
activity.setContentView(new View(context) { | |
float fontSize = 36f; | |
private TextPaint paint = new TextPaint() { | |
{ | |
setStyle(Paint.Style.FILL); | |
setColor(0xffFFFFFF); | |
setTextSize(fontSize * scaledDensity); | |
} | |
}; | |
private Paint borderPaint = new TextPaint() { | |
{ | |
setStyle(Paint.Style.FILL); | |
setColor(0x99FF0000); | |
} | |
}; | |
String ellipsizedText; | |
// String text = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."; | |
// String text = "אל זכר העיר רוסית מבוקשים. שנורו בישול צ'ט אל. ספינות רשימות אחרונים שכל ב. בה ארץ אקראי לערכים. גם שדרות ביוני גיאוגרפיה היא. ויש הבקשה רומנית אם, של המשפט העברית אווירונאוטיקה היא. כימיה ייִדיש אנא של."; | |
// String text = "Ηας ελεστραμ ασεντιορ εα, εξ πωσε νυσκυαμ δισεντιυνθ κυο. Εα εως λιβερ αυδιαμ φεριθυς. Εως υνυμ σριψεριθ αδ, κυι θε λατινε κυαεκυε περπετυα. Φις νιβχ πρωπριαε αργυμενθυμ νε."; | |
// String text = "وفي الستار فرنسية الوزراء بـ. انتهت النازيين إذ أما, بسبب فقامت الألوف أم كان, بها وبعدما إستعمل الشهير من. الثالث، الهزائم حين هو, قد فرنسية الحاملات مكن, يتم بـ تسمّى الانجليزية. إذ دحر جندي وإقامة الأمريكي،. ثم حرب بالقصف للغزو،, بعد تم بهجوم كانتا إظهارإخفاء. إحتار نتيجة أي كلا, ثم للصين العناد الحرب، حرب."; | |
// String text = "妥ど 禞じゅ氩 䧟駺.苨儥 椦杯ゐ褩きゃ コぶ焣榟嶣, せ䦎 イげ覌 갣驌榵ウゥ䥪 椦杯ゐ褩きゃ 鏨夦以バヴィェ 氧楣 槥䣃卤勩ス キャきょしゃ餥す 僯さり焯ギョ 禤谣ね, とぢょへでびゅ 櫦ヴァ詃マ て ナた かにゅ䄥, ぬ䤣䰥 짦襃ぽ綦秚 僯さり焯ギョ 槞觟ぬ䤣䰥 にゃちゅ 礯盨樃 じ壪 堥䦪そ捦褤 ゝひょ襨ル䨦, 禯ざ㠤 堥䦪 廥ぎ饃い杦 䏦べ知礯盨 褩きゃや 盤觚わ䏩みょ 蝥はりゅぞ棃 じゃ餩ばナた やきゅ り焯ギョ 脩滧䨤ぎゅぢゅ ゝひょ襨ル䨦 餩ば, 鏨夦以バヴィェ め檣㛤杧づ ウゥ䥪䧟 褩きゃ"; | |
String text = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0987654321`,Å"; | |
int index = 1; | |
int count = 0; | |
boolean reverse = false; | |
@Override protected void onMeasure(int w, int h){ | |
if (index >= 10 || index <= 1) { reverse = !reverse; } | |
paint.setTextSize(getHeight()/16 * scaledDensity * (reverse ? ++index : --index)*0.1f); | |
super.onMeasure(w,h); | |
long start; | |
start = System.nanoTime(); | |
ellipsizedText = (String) TextUtils.ellipsize(text, paint, metrics.widthPixels, TextUtils.TruncateAt.MIDDLE); | |
Log.d("thinpushclient", TextView.class.getName() + " onMeasure " + ((System.nanoTime() - start)*0.000001) + "ms"); | |
} | |
boolean goNuts = true; | |
@Override | |
public boolean onTouchEvent(MotionEvent event) { | |
goNuts = !goNuts; | |
postInvalidate(); | |
requestLayout(); | |
return super.onTouchEvent(event); | |
} | |
float top = 300; | |
float height = 0; | |
@Override protected void onDraw(Canvas canvas) { | |
++count; | |
long start = System.nanoTime(); | |
top = getHeight()/2; | |
canvas.drawColor(0xbbaadd99); | |
canvas.drawText(ellipsizedText, 0, top, paint); | |
// borderPaint.setColor(0x55FF0000); | |
// canvas.drawRect(0,top + paint.ascent(), getWidth(), top, borderPaint); | |
// borderPaint.setColor(0x5500FF00); | |
// canvas.drawRect(0,top, getWidth(), top + paint.descent(), borderPaint); | |
// borderPaint.setColor(0x550000FF); | |
// canvas.drawRect(0,top - (fontSize * scaledDensity) + paint.descent(), getWidth(), top+paint.descent(), borderPaint); | |
// | |
// borderPaint.setColor(0xffFFFFFF); | |
// borderPaint.setStyle(Paint.Style.STROKE); | |
// canvas.drawRect(0,top + paint.ascent(), getWidth(), top + paint.descent(), borderPaint); | |
Log.d("thinpushclient", TextView.class.getName() + " onDraw " + ((System.nanoTime() - start)*0.000001) + "ms"); | |
if (goNuts){ | |
postInvalidate(); | |
requestLayout(); | |
} | |
if (count >= 100) { | |
count = 0; | |
goNuts = false; | |
} | |
} | |
}); | |
} | |
} |
For those taking notes at home, that reference to SandyShorts
is the very very very first primordial exploration of what eventually became React Native. Remind me to Blast all about that one of these days.
SandyShorts
has absolutely nothing to do with AoHotView
other than the fact that I used the one to develop the other.
Oh also! I totally forgot.
Using this HotCode stuff, I created a view hierarchy inspector tool thing that eventually became integrated into some other Facebook dev tool that I completely forget the name of. But it was awesome!
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
RemoteViewActivity.java
in there somehowjava-to-dex.sh
or whatever works for youPush the generated Test.dex file to your the running app(s) and run it usingpush-dex.sh
(EDIT:
java-to-dex.sh
runspush-dex.sh
for you, so ignore step #4