OutOfMemoryError loading multiple images!! - Touch Diamond, MDA Compact IV General

Hi all,
I am developing an app which needs to load images from the My Pictures folde on the HTC Diamond...for some reason My Pictures is the root which makes it easier to connect the inut stream.... Anyway, I am only able to load a maximum of 7 images for some reason.....after this I get the dreaded outOfMemoryError. The images are a maximum of 10.0k each and I have tried loading them several fifferent ways ie with the String path,inputstream, and with a byte array after reding the data with an input stream....all with the same output. I dont see why the heap would only allow for a maximum of 7 small images or am I just not going about this the correct way. I ahve tried setting things to null and calling System.gc (which I know is just a suggestion) but this didnt help.....
I am however able to load as many images as I like from inside my jar file ie stored images in the src folder of my package??...this is not of any use to me though as I need to read images from the device itself, but thought the info may help someone see where my problem lies??
My code is as follows :
public void createImageDisplayForm() {
//get the number of files in the directory...implimented above
imgno = getNumberImages();
//grid layout increases automatically if there are more images than grid squares
imageDisplayCont = new Container(new GridLayout(2,3));
imageDisplayForm.addComponent(BorderLayout.NORTH,bannerVLabel);
directoryName=FileSystemRegistry.listRoots();
initDir=directoryName.nextElement().toString();
try {
for(int in = 0; in<imgno;in++) {
conn = (FileConnection) Connector.open("file:///"+initDir+filePaths[in],Connector.READ);
is = conn.openInputStream();
imageDisplayCont.addComponent(new Button(Image.createImage(is)));
conn.close();
is.close();
conn=null;
is=null;
System.gc();
}
}
catch(Exception e) { e.printStackTrace();}
finally {
try {
is.close();
conn.close();
}
catch(Exception e) {}
}
imageDisplayForm.addComponent(BorderLayout.CENTER,imageDisplayCont);
//display form
imageDisplayForm.show();
}
Pleas if anyone has any thoughts on this I would really appreciate them as I am stuck now.
Many thanks
Jules

Related

Is Android Programming Like Normal Java?

Right a quick question about Android Developing.
I'm a 1st year Computer Science Student, learning java. I would like to eventually be able to code for android.
Obviously android apps are coded in java so am I right that being able to use java would mean you would be able to code for android? Asside from slight differences, coding for the touchscreen etc.
For example, here is a basic Prime Number Calculator:
Code:
public static void main(String[] args) {
for (;;) {
InputFrame theInputFrame = new InputFrame();
int seqlength = theInputFrame.getInt("Length of Sequence");
int[] notcrossed = new int[seqlength];
for (int i = 0; i < seqlength; i++) {
notcrossed[i] = i + 1;
}
for (int i = 2; i < seqlength; i++) {
int times = 1;
while (i + ((i * times) - 1) <= seqlength - 1) {
notcrossed[i + ((i * times) - 1)] = 0;
times = times + 1;
}
}
// System.out.print("Prime numbers between 2 and " + seqlength + " are: ");
for (int i = 1; i < seqlength; i++) {
int primenumbers[] = new int[seqlength];
if (notcrossed[i] == 0) {
} else {
primenumbers[i - 1] = notcrossed[i];
System.out.print(primenumbers[i - 1] + " ");
}
}
System.out.println("");
}
}
Would I be right in assuming that android would understand this code? Of course with tweaks to make things display on screen, input numbers etc?
Java is Java is Java... more or less. Perhaps more less than more
Some classes you know may not exist on Android, and Android has some classes you may not be aware of. System.out.println won't do anything on android, instead, you would use Log.d("label","value") -- debug message, or Log.e() for error message. Simple dumb stuff like that.
The biggest difference that you will find is that UI stuff is typically written in XML rather than directly in Java. The various integrated widgets already handle the touchscreen events, so if you stick with them, there is nothing much you need to manage -- just some simple things, like linking a button widget to a click listener via the widget's setOnClickListener() method. A click listener is essentially just a runnable that runs in the display thread (so that it can directly affect what is showing on the screen). Also you need to read up on linking your classes with the appropriate XML screen layout file.
There's a TON of useful starting info located here: http://developer.android.com/guide/topics/fundamentals.html
Read ALL of that stuff... five times. And try out all their idiot programs. They seem simplistic, but they will help you get a feel of the platform.
Before getting start with Android, know the basic things needed for learning Android programming and app development. Basically Java plays an important role in Android app development.
I would also suggest you to get the help from online experts where they would surely help you out in learning Android programming ans app development from scratch.
I found one such tutorial @ learnsauce seems to be interesting where they not only help in learning Android programming but also in learning Android app development.

Applying changes without [soft-]rebooting

Hi, I've been gone for a long long time and just came back with a new module.
I have seen that some other modules can actually apply the changes immediately without the need of doing a soft-reboot or full reboot. That is new to me. Maybe I missed it during those times when I'm not around.
So I want to ask the masters about this technique. How do you implement it. Or is there a xposed method which is reponsible for this?
I'm trying to apply changes to resources of a package.
I hope someone can explain to me how to implement it.
Thanks in advance!
Usual scenario:
Code:
<load preferences>
<hook method>
<do something inside the method using the loaded preferences>
Dynamically:
Code:
<initialize XSharedPreferences>
<hook method>
<reload preferences using XSharedPreferences.reload() and getting the preferences directly>
<do something inside the method using the loaded preferences>
You can also use broadcasts, if possible.
GermainZ said:
Usual scenario:
Code:
<load preferences>
<hook method>
<do something inside the method using the loaded preferences>
Dynamically:
Code:
<initialize XSharedPreferences>
<hook method>
<reload preferences using XSharedPreferences.reload() and getting the preferences directly>
<do something inside the method using the loaded preferences>
You can also use broadcasts, if possible.
Click to expand...
Click to collapse
sorry but the idea really can't sink into my mind... maybe I need some actual code... but anyway sir, by using XSharedPreferences, does it mean that all inputs must be saved in a prefs file?
This module I've made does not actually utilize SharedPrreferences, but store them inside the files dir using getFilesDir() for some reason...
WisdomSky said:
sorry but the idea really can't sink into my mind... maybe I need some actual code... but anyway sir, by using XSharedPreferences, does it mean that all inputs must be saved in a prefs file?
This module I've made does not actually utilize SharedPrreferences, but store them inside the files dir using getFilesDir() for some reason...
Click to expand...
Click to collapse
Well in that case you'd just read the preferences before applying them. In some cases (resources replacements), I don't think it's possible, but if you're hooking a module to change a TextView's color for example:
Code:
beforeHookedMethod:
int textColor = getTextColor(); // load the preference inside the method
TextView textView = …;
textView.setTextColor(textColor); // apply the preference
I might be able to give you an actual example if you explain what you're doing exactly, but as I said I don't think it's possible for resource replacements (which I guess is what you're doing).
GermainZ said:
Well in that case you'd just read the preferences before applying them. In some cases (resources replacements), I don't think it's possible, but if you're hooking a module to change a TextView's color for example:
Code:
beforeHookedMethod:
int textColor = getTextColor(); // load the preference inside the method
TextView textView = …;
textView.setTextColor(textColor); // apply the preference
I might be able to give you an actual example if you explain what you're doing exactly, but as I said I don't think it's possible for resource replacements (which I guess is what you're doing).
Click to expand...
Click to collapse
When a user has selected a package, a new directory under its package name will be created inside the files dir of my app, and when the user has applied a replacement to a certain resource a new directory will be created inside the directory created a while ago. and then inside this directory is where a new file is created and the filename will be the resource name and the content of the file is just a single line plain text which is the replacement value.
so if you can see it, there is a heirarchy of directories...
under the files dir... it could look like this...
[dir]files
-----[dir]com.package.name
----------[dir]string
---------------[file]app_name
----------[dir]drawable
---------------[file]ic_launcher
by using this pattern, I can write something that will loop through the files dir... get the package name, then get the resource type, then get the resource name and finally get its value by reading the content. And now we all have the needed arguments to pass to the setReplacement method...
but since you said that it is not applicable to resource replacements, then there's really no hope.
WisdomSky said:
but since you said that it is not applicable to resource replacements, then there's really no hope.
Click to expand...
Click to collapse
I might be wrong as I'm not too familiar with replacing resources. Where are you replacing the resources? Also, can wee see a (simplified/pseudo-code, maybe) code snippet of you doing so?
The problem with resources is that the app/system will usually load resources just once, or at least only at certain spots of the code. So even if you set a new replacement, it won't come into effect immediately, but only when the app/system decides loads it again. Same for removed replacements.
WisdomSky said:
I hope someone can explain to me how to implement it.
Thanks in advance!
Click to expand...
Click to collapse
If you module hooks Activity, Service or any other context application, you can store settings not with Shared Preferences, but in system settings database and use ContextResolver to get information from database.
and of course use <uses-permission android:name="android.permission.WRITE_SETTINGS" />
Here is an example:
Code:
findAndHookMethod("com.android.phone.PhoneApp", paramLoadPackageParam.classLoader, "onCreate", new XC_MethodHook()
{
protected void beforeHookedMethod(MethodHookParam param) throws Throwable
{
ContentResolver cr = (ContentResolver) XposedHelpers.callMethod(param.thisObject, "getContentResolver");
Class <?> Features = XposedHelpers.findClass("com.android.phone.HtcFeatureList", paramLoadPackageParam.classLoader);
boolean CallRecording = Misc.toBoolean(Settings.System.getInt(cr, Const.TWEAK_CALL_REC, 0));
if (CallRecording)
{
XposedHelpers.setStaticBooleanField(Features, "FEATURE_SUPPORT_VOICE_RECORDING", true);
}
}
});
More look here https://github.com/Falseclock/HtcOneTweaker/blob/master/src/kz/virtex/htc/tweaker/mods/Recorder.java
It is possible also to implement for resources, but you have always lookup views by identifier, load your application resources, redraw drawables, strings, etc. AND THIS IS BATTERY COST EFFICIENT method.
Other way - store replaced drawables for example in static variables and do not redraw every time. But there will be a huge code if you are replacing a lot of resources.
here is another example
Code:
public static Drawable Background;
findAndHookMethod(packageName + ".ui.ConversationListBaseAdapter", paramLoadPackageParam.classLoader, "bind", "android.view.View", "android.content.Context", packageName + ".ui.ConversationHeader", new XC_MethodHook()
{
protected void afterHookedMethod(MethodHookParam param) throws Throwable
{
boolean isRead = (Boolean) XposedHelpers.callMethod(param.args[2], "isRead");
View row = (View) param.args[0];
if (Background == null)
{
Background = row.getBackground();
if (Background == null)
{
Background = new ColorDrawable(row.getContext().getResources().getColor(android.R.color.transparent));
}
}
if (isRead == false)
{
XModuleResources modRes = XModuleResources.createInstance(XMain.MODULE_PATH, null);
row.setBackgroundDrawable(modRes.getDrawable(R.drawable.list_background_unread));
} else
{
row.setBackgroundDrawable(Background);
}
}
});
Falseclock said:
If you module hooks Activity, Service or any other context application, you can store settings not with Shared Preferences, but in system settings database and use ContextResolver to get information from database.
and of course use <uses-permission android:name="android.permission.WRITE_SETTINGS" />
Here is an example:
Click to expand...
Click to collapse
Ideally, all traces of an Xposed module should be removed when it's uninstalled, IMO. This goes against that.
GermainZ said:
Ideally, all traces of an Xposed module should be removed when it's uninstalled, IMO. This goes against that.
Click to expand...
Click to collapse
Ideally yes, but there are some tweak/mods requires fast settings change and immediate apply without restart. Otherwise such mods are not usable.
I do such only for special mods. All other mods are stored in shared preferences.
Falseclock said:
Ideally yes, but there are some tweak/mods requires fast settings change and immediate apply without restart. Otherwise such mods are not usable.
I do such only for special mods. All other mods are stored in shared preferences.
Click to expand...
Click to collapse
Then get the app's context/system context and use your own settings, or register and use a BroadcastReceiver.
GermainZ said:
Then get the app's context/system context and use your own settings, or register and use a BroadcastReceiver.
Click to expand...
Click to collapse
you are completely right. I just took ready code from my old custom ROM and used as it is in Xposed mode.
time to refactor my code )))
Hi I want to blend in too so: I have charged the preferences in the initzigote and after I have method like this:
Code:
beforhookedmethod{
Pref.reload();
String[] A new string[2000];
Map<string,?> B = Pref.getall();
i=0;
for(Map.Entry<String,?> entry : a.entrySet()){
B[i] = entry.getValue().toString();
Xposedbridge.log(entry.getvalue());
i++;
}
//some code that set this array into a hooked field
}
Now the problem is:if I remove the reload pref,after a reboot all work but if I leave the reload nothing work;the method is still hooked because I see that doesn't do what it normally do,but doesn't do what I say in the hook and even no log.What could be the problem?
Thanks.
Massi-X said:
Hi I want to blend in too so: I have charged the preferences in the initzigote and after I have method like this:
Code:
beforhookedmethod{
Pref.reload();
String[] A new string[2000];
Map<string,?> B = Pref.getall();
i=0;
for(Map.Entry<String,?> entry : a.entrySet()){
B[i] = entry.getValue().toString();
Xposedbridge.log(entry.getvalue());
i++;
}
//some code that set this array into a hooked field
}
Now the problem is:if I remove the reload pref,after a reboot all work but if I leave the reload nothing work;the method is still hooked because I see that doesn't do what it normally do,but doesn't do what I say in the hook and even no log.What could be the problem?
Thanks.
Click to expand...
Click to collapse
Full code? what's Pref? How are you initializing it?
GermainZ said:
Full code? what's Pref? How are you initializing it?
Click to expand...
Click to collapse
This is the full code:
Code:
public String[] A = new String[2000];
Field B = null;
public XSharedPreferences Pref;
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
Pref = new XSharedPreferences("com.android.xposed...", "Preferences");
}
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
if (lpparam.packageName.equals("com.android...")) {
de.robv.android.xposed.XposedHelpers.findAndHookMethod
("com.android...", lpparam.classLoader, "....", Operation.class,
new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
final Class<?> Constants = de.robv.android.xposed.XposedHelpers.findClass
("....", lpparam.classLoader);
Pref.reload();
Map<String,?> D = xPreferences.getAll();
int i=0;
for (Map.Entry<String, ?> entry: D.entrySet()) {
A[i] = entry.getKey();
de.robv.android.xposed.XposedBridge.log(entry.getKey());
i++;
}
B = de.robv.android.xposed.XposedHelpers.findField
(Constants, "ACCEPTABLE...");
final Object oldFieldAcc = B.get(Constants);
B.set
(oldFieldAcc, A);
});
}
}
}
I want to keep the secret so I obscured the name of variables and some string but all the code is exactly that!
Thanks!
Massi-X said:
This is the full code:
Click to expand...
Click to collapse
And it works fine when you remove .reload()? I'm not sure what's wrong, but if I had to guess, I'd say it's a permission issue. Do this when defining Pref instead:
Code:
Pref = new XSharedPreferences(…, …);
[COLOR="Red"]Pref.makeWorldReadable();[/COLOR]
GermainZ said:
And it works fine when you remove .reload()? I'm not sure what's wrong, but if I had to guess, I'd say it's a permission issue. Do this when defining Pref instead:
Code:
Pref = new XSharedPreferences(…, …);
[COLOR="Red"]Pref.makeWorldReadable();[/COLOR]
Click to expand...
Click to collapse
Yes works perfect when I remove to reload.I have yet tried this solution but not work.
I try to explain you what happens when I use the version with pref.reload:I select the option in my app and reboot and all work,also the log;when I change things on the go old preferences continue to work and the hook also but all new things aren't considered and the log stop to work.
I'm going crazy....
That's easy to explain: You write the settings from your own app, but read them from a different app. It doesn't matter that your code tries to read the settings, it's executed in the hooked app's process with the hooked app's UID. Android's security concept doesn't allow this by default, preferences are usually only readable for the app that created it. Pref.makeWorldReadable() will change this (as the name says), but Android automatically resets the permissions when you store the settings again. To fix this, try:
Code:
[B]getPreferenceManager().setSharedPreferencesMode(MODE_WORLD_READABLE);[/B]
addPreferencesFromResource(R.xml.preferences);
https://github.com/rovo89/PlayStore...d/mods/playstorefix/SettingsActivity.java#L29
rovo89 said:
That's easy to explain: You write the settings from your own app, but read them from a different app. It doesn't matter that your code tries to read the settings, it's executed in the hooked app's process with the hooked app's UID. Android's security concept doesn't allow this by default, preferences are usually only readable for the app that created it. Pref.makeWorldReadable() will change this (as the name says), but Android automatically resets the permissions when you store the settings again. To fix this, try:
Code:
[B]getPreferenceManager().setSharedPreferencesMode(MODE_WORLD_READABLE);[/B]
addPreferencesFromResource(R.xml.preferences);
https://github.com/rovo89/PlayStore...d/mods/playstorefix/SettingsActivity.java#L29
Click to expand...
Click to collapse
You won't believe it but i think this last night .And yes,this was the problem!Thanks to everyone have help me.I think that my module will online today or tomorrow. :good:

findClass() returning java.lang.Class

When i am trying to call a method (to start the music in grooveshark) i come across an error that i believe is because XposedHelpers.findClass() is returning an unwanted class.
Here is the code that is giving the issue
Code:
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
XposedHelpers.callMethod(XposedHelpers.findClass("com.grooveshark.android.lib.player.AsyncPlayer", lpparam.classLoader),"play", true);
}
And here is the error that it is returning
Code:
08-20 01:30:31.038 2390-2390/? I/Xposed﹕ java.lang.NoSuchMethodError: java.lang.Class#play(java.lang.Boolean)#bestmatch
at de.robv.android.xposed.XposedHelpers.findMethodBestMatch(XposedHelpers.java:271)
at de.robv.android.xposed.XposedHelpers.findMethodBestMatch(XposedHelpers.java:284)
at de.robv.android.xposed.XposedHelpers.callMethod(XposedHelpers.java:947)
...
This error is here because callMethod should be calling
Code:
com.grooveshark.android.lib.player.AsyncPlayer#play
but instead it calls
Code:
java.lang.Class#play
because "Class" is being passed to it from findClass, not the correct class
What needs to be done to get the right class/call the right method?
Edit:
i have tried using param.thisObject, but the method i want (play) is in a different package than the onStart method (that i am hooking). The method i am hooking (onStart) is in
Code:
com.grooveshark.android.v1.activity.Home
and using param.thisObject just gives me
Code:
java.lang.NoSuchMethodError: com.grooveshark.android.v1.activity.Home#play(java.lang.Boolean)#bestmatch
as it is in the wrong package
I'm assuming play is a static method, since you wouldn't be able to call it without an instance otherwise.
If that's the case, you should use XposedHelpers.callStaticMethod.
GermainZ said:
I'm assuming play is a static method, since you wouldn't be able to call it without an instance otherwise.
If that's the case, you should use XposedHelpers.callStaticMethod.
Click to expand...
Click to collapse
When i changed it to
Code:
XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.grooveshark.android.lib.player.AsyncPlayer", lpparam.classLoader),"play", true);
I get the error
Code:
I/Xposed﹕ java.lang.NullPointerException: expected receiver of type com.grooveshark.android.lib.player.AsyncPlayer, but got null
That being said...if i hook into a method in the same class as play, i will use the 'pause' method as an example, and call
Code:
XposedHelpers.callMethod(param.thisObject,"play", true);
then play is correctly called (which has the unfortunate effect of preventing me from stopping the music)
So i still think the issue is that i do not know how to correctly use findClass/callMethod
Here is "play"
Code:
public void play(boolean paramBoolean) {
while (true) {
try {
if (this.context == null) {
this.logger.severe("No context set! Has the player been released?");
return;
}
if (this.playableSong == null) {
this.logger.severe("playableSong not set!");
continue;
}
} finally {}
this.logger.info("playing " + getPlayableSong() + " current state: " + this.state.name() + ", successive? " + paramBoolean);
this.isSuccessive = paramBoolean;
this.isPaused = false;
if (this.state != State.PAUSED) {
State localState1 = this.state;
State localState2 = State.PREPARED;
if (localState1 != localState2);
} else {
try {
this.mp.start();
setState(State.PLAYING);
startPolling();
} catch (IllegalStateException localIllegalStateException) {
this.mp.reset();
setState(State.IDLE);
}
continue;
}
if (this.state == State.PREPARING) {
this.handler.sendEmptyMessage(2);
} else {
setState(State.PREPARING);
Message localMessage = this.handler.obtainMessage(0, this.context);
this.handler.sendMessage(localMessage);
}
}
}
dillonr said:
When i changed it to
Code:
XposedHelpers.callStaticMethod(XposedHelpers.findClass("com.grooveshark.android.lib.player.AsyncPlayer", lpparam.classLoader),"play", true);
I get the error
Code:
I/Xposed﹕ java.lang.NullPointerException: expected receiver of type com.grooveshark.android.lib.player.AsyncPlayer, but got null
That being said...if i hook into a method in the same class as play, i will use the 'pause' method as an example, and call
Code:
XposedHelpers.callMethod(param.thisObject,"play", true);
then play is correctly called (which has the unfortunate effect of preventing me from stopping the music)
So i still think the issue is that i do not know how to correctly use findClass/callMethod
Here is "play"
Code:
public void play(boolean paramBoolean) {
while (true) {
try {
if (this.context == null) {
this.logger.severe("No context set! Has the player been released?");
return;
}
if (this.playableSong == null) {
this.logger.severe("playableSong not set!");
continue;
}
} finally {}
this.logger.info("playing " + getPlayableSong() + " current state: " + this.state.name() + ", successive? " + paramBoolean);
this.isSuccessive = paramBoolean;
this.isPaused = false;
if (this.state != State.PAUSED) {
State localState1 = this.state;
State localState2 = State.PREPARED;
if (localState1 != localState2);
} else {
try {
this.mp.start();
setState(State.PLAYING);
startPolling();
} catch (IllegalStateException localIllegalStateException) {
this.mp.reset();
setState(State.IDLE);
}
continue;
}
if (this.state == State.PREPARING) {
this.handler.sendEmptyMessage(2);
} else {
setState(State.PREPARING);
Message localMessage = this.handler.obtainMessage(0, this.context);
this.handler.sendMessage(localMessage);
}
}
}
Click to expand...
Click to collapse
If play is a static method: use callStaticMethod.
If play is not a static method: you can't use findClass to call it, you'll need the class' instance.
GermainZ said:
If play is a static method: use callStaticMethod.
If play is not a static method: you can't use findClass to call it, you'll need the class' instance.
Click to expand...
Click to collapse
play isn't static...How would i get the class' instance?
dillonr said:
play isn't static...How would i get the class' instance?
Click to expand...
Click to collapse
Using getObjectField, assuming there is one. If not, you can try creating an instance (using the newInstance method, IIRC).
I'd think if this is the right way to do it, though. Although I don't know what you're trying to do, it sounds like you should be hooking a different method.
GermainZ said:
Using getObjectField, assuming there is one. If not, you can try creating an instance (using the newInstance method, IIRC).
I'd think if this is the right way to do it, though. Although I don't know what you're trying to do, it sounds like you should be hooking a different method.
Click to expand...
Click to collapse
Hopefully this clears it up...What i am trying to do is have grooveshark automatically play music when my phone connects to the bluetooth speakers in my car
Currently i am working out how to make the music play, but i already have the code there to check that bluetooth is connected (although untested, as i wrote it last night and haven't been out to the car to check it).
When i am finished, tasker will open grooveshark when my phone connects to the bluetooth speakers and my xposed module will check that bluetooth is connected and then start playing the music. Hooking onto the onStart method seemed to be the easiest way to get everything going when grooveshark opens
Would it be possible to see an example of getObjectField/newInstance? I promise i have tried to figure it out myself, i'm just not sure what to do, and looking at the source of XposedHelpers.java gives me an idea of what is available, but not of how to use what is available
dillonr said:
Hopefully this clears it up...What i am trying to do is have grooveshark automatically play music when my phone connects to the bluetooth speakers in my car
Currently i am working out how to make the music play, but i already have the code there to check that bluetooth is connected (although untested, as i wrote it last night and haven't been out to the car to check it).
When i am finished, tasker will open grooveshark when my phone connects to the bluetooth speakers and my xposed module will check that bluetooth is connected and then start playing the music. Hooking onto the onStart method seemed to be the easiest way to get everything going when grooveshark opens
Would it be possible to see an example of getObjectField/newInstance? I promise i have tried to figure it out myself, i'm just not sure what to do, and looking at the source of XposedHelpers.java gives me an idea of what is available, but not of how to use what is available
Click to expand...
Click to collapse
OK, here's a general post that should show you how to use various methods, along with some common pitfalls.
I'm not going to write complete code, so use this as an example but don't copy/paste.
If you're using an app to view this post, I'd recommend you open it in a web browser so you get pretty syntax highlighting and formatting.
Let's assume we have two classes, Class1 and Class2. Class1:
Java:
class Class1 {
Object someVariable;
final static int SOME_FINAL_STATIC_INT = 30;
Context context;
Class2 class2Instance;
method void Class1(Context context) {
this.context = context;
class2Instance = Class2.getInstance(context);
}
method void someMethod(String stringArg, int intArg) {
for (int i = intArg; i < SOME_FINAL_STATIC_INT ; i++) {
class2Instance.doSomething(stringArg);
}
}
}
Class2:
Java:
class Class2 {
Context context;
Class2 instance;
method void Class2(Context context) {
this.context = context;
instance = this;
}
static method Class2 getInstance(Context context) {
if (instance == null)
instance = new Class2(context);
return instance;
}
method void doSomething(String stringArg) {
// do something
}
}
We want to change someMethod's behavior so it always goes from 0 to 10 instead of intArg to SOME_FINAL_STATIC_INT .
We know that we can modify the arguments of a method directly (using param.args[index]) and a static int field using setStaticInt, so it should be easy to do… right? Nope.
Why not? Because SOME_FINAL_STATIC_INT , being static and final, will be replaced by the compiler. In other words, this:
Java:
for (int i = intArg; i < SOME_FINAL_STATIC_INT ; i++) {
class2Instance.doSomething(stringArg);
}
Will actually become this when compiled:
Java:
for (int i = intArg; i < 30; i++) {
class2Instance.doSomething(stringArg);
}
So, how do you replace the 30 now? You don't. Depending on the situation, you'll have to use alternative ways to accomplish what you want. The most general one is to replace the method:
Java:
findAndHookMethod("my.package.Class1", lpparam.classLoader, "someMethod", String.class, int.class, new XC_MethodReplacement() {
[PLAIN]@Override[/PLAIN]
Object replaceHookedMethod(param) {
// we want to go from 0 to 10 only
for (int i = 0; i < 10; i++) {
// get class2Instance
Object class2Instance = getObjectField(param.thisObject, "class2Instance");
// call doSomething
callMethod(class2Instance, doSomething, param.args[0]);
}
}
});
And we're done. We wanted to modify the for loop, and we did. We then wanted to call a method, but since that method belongs to another class, we needed that class' instance first.
Assume we don't have an instance of the class, what do we do then? Well, you could create an instance yourself… but keep in mind this may not lead to the result you want if the application expects (and uses) only one instance.
For example, let's assume there was no class2Instance in Class1. We could create one like this:
Java:
findAndHookMethod("my.package.Class1", lpparam.classLoader, "someMethod", String.class, int.class, new XC_MethodReplacement() {
[PLAIN]@Override[/PLAIN]
Object replaceHookedMethod(param) {
// we want to go from 0 to 10 only
for (int i = 0; i < 10; i++) {
// find Class2
Class Class2 = findClass("my.package.Class2", lpparam.classLoader);
// we need to get a context to create an instance of Class2, since its constructor needs a context
Context context = (Context) getObjectField(param.thisObject, "context");
// create class2Instance
Object class2Instance = newInstance(Class2, context);
// we can also call Class2.getInstance, which would be a better choice, although such a method is not always available.
// Object class2Instance = callStaticMethod(Class2, "getInstance", context);
// call doSomething
callMethod(class2Instance, doSomething, param.args[0]);
}
}
});
To recap: we got the context using getObjectField, just as before.
We then got the Class for Class2 and used it to create a new instance. (We also could've called the static method, which would have given us the existing instance, if any; such a method isn't always available, though).
The rest was similar to the previous example.
I hope this explains how to use some of the methods Xposed offers clearly. Good luck.
I am still unable to call a method (i think that it is because the method i am calling is in a different package (.lib.player.AsyncPlayer) than the one i am hooking (.v1.activity.Home), so i can't get a context/instance.)
I think it is time that i drop this module, and spend my time elsewhere, maybe coming back to it later when i learn more
dillonr said:
I am still unable to call a method (i think that it is because the method i am calling is in a different package (.lib.player.AsyncPlayer) than the one i am hooking (.v1.activity.Home), so i can't get a context/instance.)
I think it is time that i drop this module, and spend my time elsewhere, maybe coming back to it later when i learn more
Click to expand...
Click to collapse
Your issue has been addressed in the legacy thread. See this and [URL="http://forum.xda-developers.com/showpost.php?p=40166637&postcount=980]this[/URL]
NipplesOfTheFuture said:
Your issue has been addressed in the legacy thread. See this and [URL="http://forum.xda-developers.com/showpost.php?p=40166637&postcount=980]this[/URL]
Click to expand...
Click to collapse
If all he needs is a context, he can simply use AndroidAppHelper.currentApplication().

How to take a screenshot from within an XPosed module?

Hi,
First off, I just entered the android programming world so my knowledge is very limited. Please bear with me.
I'm creating an XPosed module that simply takes a screenshot when I press the volume up or down buttons.
I've managed to hook the buttons globally, but since I don't have control of the topmost view, I don't know how I would be able to take a screenshot.
Originally, one would do it this way :
Code:
public Bitmap screenShot(View view) {
Bitmap bitmap = Bitmap.createBitmap(view.getWidth(),
view.getHeight(), Config.ARGB_8888);
Canvas canvas = new Canvas(bitmap);
view.draw(canvas);
return bitmap;
}
screenShot((ViewGroup) view.getParent());
However, I would need the view of the current activity in the foreground, and I'm kind of lost on how to retrieve it from within the XPosed module.
I looked through XPosedHelper.class and found a bunch if "find" functions that can get methods, resources, and classes but there are no helper functions for views except this comment on the very end.
Code:
// TODO helpers for view traversing
My current code looks like this :
Code:
public class Main {
static void init() {
try {
Class<?> classPhoneWindowManager = findClass("com.android.internal.policy.impl.PhoneWindowManager", null);
findAndHookMethod(classPhoneWindowManager, "interceptKeyBeforeQueueing",
KeyEvent.class, int.class, boolean.class, handleInterceptKeyBeforeQueueing);
} catch (Exception e) { XposedBridge.log(e); }
}
private static XC_MethodHook handleInterceptKeyBeforeQueueing = new XC_MethodHook(XCallback.PRIORITY_HIGHEST) {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
final boolean isScreenOn = (Boolean) param.args[2];
if (isScreenOn) {
final KeyEvent event = (KeyEvent) param.args[0];
final int keyCode = event.getKeyCode();
if (keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP) {
if (event.getAction() == KeyEvent.ACTION_DOWN) {
doSomething(param.thisObject, keyCode);
param.setResult(0);
return;
}
}
}
}
};
private static void doSomething(Object phoneWindowManager, int keycode) {
View content = findViewById(R.id.layoutroot);
content.setDrawingCacheEnabled(true);
}
}
I have to put some code in the "doSomething" function, but I'm kind of lost apprently. :crying:
How could I go about getting the screenshot of the current screen?
I've tried accessing the framebuffer, but realized that the framebuffer has been removed and only an empty fb0 exist on recent devices.
I also tried to use "/system/bin/screencap, screenshot, screenrecord" but for some reason, the application I'm targeting doesn't seem to work with those binaries.
Do you have any other suggestions? Any help would be appreciated.
Thanks.
You can use the APP called aiogestures,,Then you can change holding the menu button to screenshot button,or you can use the gravitybox to change the button………………
My English Is not very good……………
wish you can solve it???
仰天坏笑 said:
You can use the APP called aiogestures,,Then you can change holding the menu button to screenshot button,or you can use the gravitybox to change the button………………
My English Is not very good……………
wish you can solve it
Click to expand...
Click to collapse
Okay, I'll try those. Thanks!
However, it would be nice if I could implement my own code to directly get screenshots, instead of using an existing device's screenshot functionality. The reason being is, the application I'm targeting prohibits the user to take a screenshot, and therefore blocks all sorts of canonical methods to take a screenshot. I would like to have some more versatility and implement custom code to test different things, so I could bypass the screenshot restriction.
My android programming skills are quite poor... so any kind of help would be appreciated.
Thanks!
The great thing about open source is that you can use the work of others as a reference, so everyone benefits from everyone.
Luckily quite some Xposed developers do publish their sources.
A safe bet is to use GravityBox by the great @C3C076 as it implements a screenshot function..
Going to GravityBox at Github and searching (press T at github) for screenshot e.g. brings up the ScrreenshotTile.java
Here is a reference to the ModHwKeys.java - and there you'll find a takeScreenshot() function.
Cheers :fingers-crossed:
tonyp said:
The great thing about open source is that you can use the work of others as a reference, so everyone benefits from everyone.
Luckily quite some Xposed developers do publish their sources.
A safe bet is to use GravityBox by the great @C3C076 as it implements a screenshot function..
Going to GravityBox at Github and searching (press T at github) for screenshot e.g. brings up the ScrreenshotTile.java
Here is a reference to the ModHwKeys.java - and there you'll find a takeScreenshot() function.
Cheers :fingers-crossed:
Click to expand...
Click to collapse
Thanks!
However, it uses a service provided in "com.android.systemui.screenshot.TakeScreenshotService", which is blocked by the application. I'm trying to use various codes of taking screenshots, but all most of them require the current foreground view that is on the screen. I'm trying to figure out how I can get the foreground view class reference from within the XPosed module.
Any other suggestions?
android.view.SurfaceControl has some static methods for capturing screenshots silently. You can even control which layers should be excluded. E.g. you can do screenshot without system decors (navbar / status bar). Refer to https://android.googlesource.com/pl...r1/core/java/android/view/SurfaceControl.java (link is for lollipop but the same class exists in lower versions, too)
Here's an example how I use it on KitKat
https://github.com/GravityBox/Gravi...m/ceco/kitkat/gravitybox/ModDisplay.java#L446
binhexcraft said:
Thanks!
... which is blocked by the application....
Click to expand...
Click to collapse
Out of curiosity. Which app are you targeting?
C3C076 said:
android.view.SurfaceControl has some static methods for capturing screenshots silently. You can even control which layers should be excluded. E.g. you can do screenshot without system decors (navbar / status bar). Refer to https://android.googlesource.com/pl...r1/core/java/android/view/SurfaceControl.java (link is for lollipop but the same class exists in lower versions, too)
Here's an example how I use it on KitKat
https://github.com/GravityBox/Gravi...m/ceco/kitkat/gravitybox/ModDisplay.java#L446
Click to expand...
Click to collapse
Just tried it out and it works perfectly!!!
..............when the app is not running. When the app is running, then it gets blocked at :
Code:
final Bitmap bmp = (Bitmap) XposedHelpers.callStaticMethod(
XposedHelpers.findClass("android.view.SurfaceControl", null), "screenshot",
naturalW, naturalH, 0, 22000);
and when I look at the debug log, it says
"FB is protected: PERMISSION_DENIED"
This happens to be because the app is configured to use a "secure window".
Do you know if there is any workaround for this restriction?
My current thinking is to hook "captureScreenImplLocked" from here :
https://android.googlesource.com/pl...74/services/surfaceflinger/SurfaceFlinger.cpp
and make it bypass this part of the code.
Code:
if (hw->getSecureLayerVisible()) {
ALOGW("FB is protected: PERMISSION_DENIED");
return PERMISSION_DENIED;
}
or maybe just hook "getSecureLayerVisible" to always return false...
Would this be the right way to go?
...but before that, is it even possible? Cause I saw a post from someone saying that hooking SurfaceFlinger is not feasible or very disruptive...
http://forum.xda-developers.com/showpost.php?p=46388379&postcount=186
Or is there maybe a better, simpler way?
Thanks!
AA1973 said:
Out of curiosity. Which app are you targeting?
Click to expand...
Click to collapse
Sent you PM.
Answer to my own question.
I found a really simple workaround.
http://repo.xposed.info/module/fi.veetipaananen.android.disableflagsecure
Thanks for all the advice guys!!
I have finally fulfilled my objective.

Google API location and fragments Help

Hello all,im new to android development and need some help,first of all my whole project been setup using the Google Navigation Drawer sample and i followed a guide which utilise in fragment classes.
I want to implement a location that updates frequently and i was following a tutorial from androidHive.info
The problem i have are 2 major error in my code which i can't seem to fix apart from changing the Fragment class to Fragment Activity,but when i do i get problems with the Navigation drawer which tells me i need change it which i understand how but i also get problem with that.
But i want first see if i can fix the code without changing the Fragment class,the 2 errors i get are:
1st says GooglePlayServicesAvailable(android.context.Context) in GooglePlayService.Util cannot be applied and GeterrorDialog() in GooglePlayService.Util cannot be applied to because its not an Activity class which i have established.
pedometer.class:
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil
.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
Play_Service).show();
}
}
return false;
}
Click to expand...
Click to collapse
2nd error Builder(android.context.Context) cannot be applied:
protected synchronized void buildGoogleApiClient() {
GoogleAPI = new GoogleApiClient.Builder(this)
.addConnectionCallbacks(this)
.addOnConnectionFailedListener(this)
.addApi(LocationServices.API).build();
}
Click to expand...
Click to collapse
Is there any way to work around this without changing the Fragment to a FragmentActivity class?
If i have to change to FragmentActivity how would i work about fixing this part:
I have highlighted the main problem and i understand i need use getSupportFragmentManager but when i do change it and import correctly i get the same problem still.
MainActivity.class
Fragment fragments = null;
switch (position) {
case 0:
fragments = new pedometer();
break;
case 1:
fragments = new map();
break;
case 2:
fragments = new statspage();
}
FragmentManager fragmentManager = getFragmentManager();
fragmentManager.beginTransaction()
.replace(R.id.container, fragments)
.commit();
}
Click to expand...
Click to collapse
Much advice or correction would be appreciated so i can learn from it,i have been looking for a long time for some solution but couldn't really find any. I'm sure its something silly mistake i have made and would love to point at right direction.

Categories

Resources