Screenshot einer Activity erstellen und abspeichern

  • 47 Antworten
  • Letztes Antwortdatum
FelixL

FelixL

Ehrenmitglied
821
Ich versuche Änderungen am System vorzunehmen, um bei jedem Aufrufen von onPause einen Screenshot der Activity abzuspeichern.

(Der Grund dafür ist eigentlich hier angegeben, falls es jemanden interessiert:
https://www.android-hilfe.de/forum/android-app-entwicklung.9/failed-binder-transaction.46480.html
Ich will die offizielle Api erhalten, aber trotzdem Screenshots in der vollen Auflösung bekommen.)

Dafür muss ich einige Änderungen im System vornehmen, vor allem in der Datei ActivityThread.java:
android.git.geo.kernel.org Git - platform/frameworks/base.git/blob - core/java/android/app/ActivityThread.java

Das hier sind meine Veränderungen:
Dieser Teil wird aufgerufen wenn die Activity pausiert wird. Ich hab sie in die Funktion performStopActivityInner() eingefügt, direkt hinter
//info.thumbnail = createThumbnailBitmap(r);
(Das ist die deaktivierte offizielle Api.)

Der Code macht nicht viel, er ruft nur eine eigene Funktion für die eigentliche Erstellung des Screenshots auf, und speichert diese Bitmap dann mittels openFileOutput().
Code:
                	Bitmap bigThumbnail = createBigThumbnailBitmap(r);
                	if (bigThumbnail != null){
                		try {
                			   FileOutputStream fos= r.activity.openFileOutput("applicationThumbnail.jpg",
                			      Context.MODE_WORLD_READABLE);

                			   bigThumbnail.compress(Bitmap.CompressFormat.PNG, 90, fos);

                			   fos.flush();
                			   fos.close();
                			   } catch (Exception e) {
                			   Log.e("BigThumbnailAddon", e.toString());
                			}
                	}

Das ist meine veränderte createThumbnailBitmap(r):
Code:
private int mBigThumbnailWidth = -1;
    private int mBigThumbnailHeight = -1;
    
    private final Bitmap createBigThumbnailBitmap(ActivityRecord r) {
        Bitmap bigThumbnail = null;
        try {
            int w = mBigThumbnailWidth;
            int h;
            if (w < 0) {
                Resources res = r.activity.getResources();
                mBigThumbnailHeight = h =
                    res.getDimensionPixelSize(com.android.internal.R.dimen.big_thumbnail_height);

                mBigThumbnailWidth = w =
                    res.getDimensionPixelSize(com.android.internal.R.dimen.big_thumbnail_width);
            } else {
                h = mBigThumbnailHeight;
            }

            // XXX Only set hasAlpha if needed?
            bigThumbnail = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
            bigThumbnail.eraseColor(0);
            Canvas cv = new Canvas(bigThumbnail);
            if (!r.activity.onCreateThumbnail(bigThumbnail, cv)) {
            	bigThumbnail = null;
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
                throw new RuntimeException(
                        "Unable to create bigThumbnail of "
                        + r.intent.getComponent().toShortString()
                        + ": " + e.toString(), e);
            }
            bigThumbnail = null;
        }

        return bigThumbnail;
    }

Was noch zu sagen ist:
ich hab keine Ahnung wie ich ein ganzes Android quasi in Eclipse importieren kann oder sowas, um dort schon mal Fehlermeldungen auszuschließen. Ich hab nur mal die Activity-Tread.java importiert, und die meisten Fehler konnte ich damit erschlagen. Die die jetzt noch angezeigt werden liegen (hoffentlich) an fehlenden Importen und Klassen drumrum.

Jetzt sind für mich allerdings noch einige Fragen offen:
1) Ich will in values.xml in der framework.res zwei weitere Werte hinzufügen.
Dort gibt es schon
thumbnail_width und thumbnail_height
ich will
big_thumbnail_width und big_thumbnail_height
mit einbauen, funktioniert das einfach so das ich sie dort einfach nur hinzufüge und das System findet sie?
Bei einer normalen Android-App ist das ja ähnlich aufgebaut, aber hab ich was vergessen was Eclipse vielleicht automatisch macht?

2) Ich will dann in der Activity die Funktion openFileOutput() aufrufen, die als default in den Ordner data/data/packagename speichert. Andere Funktionen der Activity werden einfach über r.activity.FUNKTION aufgerufen, das sollte dann hier auch so klappen, oder?
Beispiel:
Zeile 3642 r.activity.onDestroy();

Glaubt ihr das funktioniert so?
Ich kompiliere das ganze dann nicht selbst sondern gebe es an Feeyo weiter, ist es ein großer Aufwand das zu machen?

Wäre sehr cool wenn jemand irgendwas dazu sagen kann, da ich mir ein einerseits relativ sicher bin das das funktioniert, sowas aber zum ersten mal mache und es nicht selbst testen kann.
 
Zuletzt bearbeitet:
befindet sich in /system/framework/core.jar bzw. wenn du kein deodexed rom hast, wovon auszugehen ist, dann in core.odex.
Also zuerst die core.odex deodexen mit baksmali, dann mit smali classes.dex erstellen und in die core.jar packen; anschließend kannst du es mit apktool dekompilieren.

Dann findest du dort irgendwo deine gesuchte Klasse, diese enthält dann aber keinen java code, sondern irgendwas anderes. :D
Es soll wohl gehen, in diesen code java code einzufügen; anschließend mit apktool wieder kompilieren und aufs Gerät pushen.

Gibt von JesusFreeke (Entwickler von apktool) ein Video dazu auf Youtube.

Achso, du willst dir den Source vom git ziehen und dein eigenes framework bauen..
 
Zuletzt bearbeitet:
  • Danke
Reaktionen: FelixL
Um die Uhrzeit bin ich auch nicht mehr so aufnahmefähig, macht nix :D
Es war aber ansich schon richtig das ich den Code einfach nur zum Laufen bringen will.
Die baksmali-Variante ist für mich aber quasi raus, da ich ja z.B. den einen Teil meines Codes an der richtigen Stelle einfügen muss, und ich nicht glaube das ich diese finde ;)

Wenn es komplizierter wird den Code zum laufen zu bringen, du aber auch glaubst das das so funktioniert, dann geb ich den anstrengenden Teil einfach an Feeyo ab, der kann das besser :p
 
ach, Code finden ist eigentlich nicht das hauptproblem.
Du kennst den Code ja von AOSP, und der in deinem handy wird sich wohl davon nicht unterscheiden.

Methodennamen und Variablennamen bleiben nämlich erhalten. ;)
 
Gut, dann probiere ich diese Variante am Wochenende (vorher leider keine Zeit :/):

Also zuerst die core.odex deodexen mit baksmali, dann mit smali classes.dex erstellen und in die core.jar packen; anschließend kannst du es mit apktool dekompilieren.

Hab auch in dem Code da oben noch vergessen das ich die Werte für die Größe je nach Orientierung (Landscape/Portrait) tauschen muss.
Aber wie gesagt, mal sehen was das Wochenende bringt.
Danke für deine Hilfe.

Nachschlag: Hey, dann kann ich mir am Wochenende ein aktuelles Rom drauf ziehen und muss nicht mehr mit ner älteren Version arbeiten nur weil dort die offizielle Api aktiviert ist. Genial :)
Wenn das so funktioniert wie du das sagst ist das echt einfach...genial ^^
 
Code:
    private final Bitmap createBigThumbnailBitmap(ActivityRecord r) {
        Bitmap bigThumbnail = null;
        try {
            int w = mBigThumbnailWidth;
            int h;
            Resources res = r.activity.getResources();
            if (w < 0) {
                mBigThumbnailHeight = h =
                    res.getDimensionPixelSize(com.android.internal.R.dimen.big_thumbnail_height);

                mBigThumbnailWidth = w =
                    res.getDimensionPixelSize(com.android.internal.R.dimen.big_thumbnail_width);
            } else {
                h = mBigThumbnailHeight;
            }
            //Swap values depending on orientation:
            if (res.getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE){
            	int tmpSwap = h;
            	h = w;
            	w = tmpSwap;
            }
            // XXX Only set hasAlpha if needed?
            bigThumbnail = Bitmap.createBitmap(w, h, Bitmap.Config.RGB_565);
            bigThumbnail.eraseColor(0);
            Canvas cv = new Canvas(bigThumbnail);
            if (!r.activity.onCreateThumbnail(bigThumbnail, cv)) {
            	bigThumbnail = null;
            }
        } catch (Exception e) {
            if (!mInstrumentation.onException(r.activity, e)) {
                throw new RuntimeException(
                        "Unable to create bigThumbnail of "
                        + r.intent.getComponent().toShortString()
                        + ": " + e.toString(), e);
            }
            bigThumbnail = null;
        }

        return bigThumbnail;
    }

Jetzt auch orientation-aware ;)
 
Das Rom ist anscheinend deodexed, eine core.odex findet er nicht, dafür aber die core.jar, die auch eine classes.dex enthält. Wenn ich jetzt noch den Code finden würde ;)

Im Ernst, hast du ne Ahnung in welcher Unterdatei das das sein könnte? Ich finde da Haufenweise allgemeinen Java-Zeug, aber nichts was nach Android aussieht...ausser einem Dalvik-Verzeichnis.
Kann ich dir die core.jar mal schicken?
 
ist doch gut, wenn es ein deodexed rom ist.
Dann einfach mit apktool dekompilieren.
Anschließend hast du einen Ordner mit dem ganzen Code unso.
Anschließend hast du für jedes Package einen Ordner.. also java, android, app, etc. und in diesen befinden sich die .smali files.
 
Ja, apktool hatte ich schon benutzt, hatte mir das mal so erschlossen das die ersten Schritte einfach wegfallen ;)

Ordnerstruktur:
-apktool.yml
-smali
com
dalvik
java
javax
junit
org
SQLite
sun

Um nur mal die obersten Ordner zu zeigen.
Manche haben noch Unterordner, in manchen sind auch direkt die smali-Dateien.
Aber wie gesagt, ich finde nichts was in die Richtung Android oder ActivityThread gehen könnte :/
 
haha
ich will mich gerade auch dort zu schaffen machen (an der Activity.java) und finde die auch nicht in der core.jar :cursing:

Edit: habs. guck in die framework.jar
 
Zuletzt bearbeitet:
:D
Wenn du was rausfindest, sag Bescheid. Ich hab keine Ahnung ^^
 
Nachschlag: Vielleicht doch...
apktool macht ja auch erst mal ne Runde baksmali. baksmali hatte aber lange Probleme mit Froyo-Apps. Vielleicht liegt es daran, das die baksmali-Version in apktool veraltet ist?
 
siehe edit :p
 
Das ist natürlich besser.
Ich machs trotzdem erst morgen, muss erst mal das Galaxy meiner Freundin mit der neuesten Nigthly beglücken ;). Danke für die ganzen Infos!
 
da apktool ja nicht geht, muss ich auf die java Methode verzichten. :mellow:
Nur leider gibt smali garkeinen Output wenn beim rekompilieren von smali code iwas nicht stimmt. Der kompiliert dann die entsprechenden Klassen einfach nicht und der boot prozess verwandelt sich eine reboot schleife. -_-
 
Ich hab grad mal die framework.jar mit apktool decompiliert, ohne Änderung compiliert und über ein update.zip gepusht. erstes hochfahren hat lange gedauert (ca. 10 min) dann war es sehr langsam am Anfang, aber es hat funktioniert.
Hast du es anders gepusht oder Änderungen an der framework.jar gemacht?
Wenn du es nur anders gepusht hast, versuch es mal mit einer update.zip, die framework-res.apk geht afaik auch nur so ohne reboots.
 
Fr4gg0r schrieb:
Es soll wohl gehen, in diesen code java code einzufügen; anschließend mit apktool wieder kompilieren und aufs Gerät pushen.

Gibt von JesusFreeke (Entwickler von apktool) ein Video dazu auf Youtube.
Einfach einfügen und mit apktoo kompilieren ist leider nicht möglich.
Der regt sich schon über alle { auf :D

Also muss ich schauen ob ich das in smali-Code geschrieben bekomme, oder eine App bauen die den Java-Code beinhaltet, den mit apktool auseinandernehmen, und dann rüberkopieren :D
Oder vielleicht einfach doch Feeyo fragen...
 
So langsam kann ich smali besser als Java ;)
 
Na dann lass deiner Lust ruhig freien Lauf, der Code steht auf der ersten Seite :D

Ich mach das morgen Früh, die Laune meiner Freundin sinkt gerade exponentiell...
 

Ähnliche Themen

DerOhneNick
Antworten
3
Aufrufe
1.427
DerOhneNick
DerOhneNick
J
Antworten
1
Aufrufe
1.319
mblaster4711
mblaster4711
Foh
Antworten
8
Aufrufe
1.848
Foh
Foh
Zurück
Oben Unten