So I've created module to hijack an app's onPictureTaken callback method to manipulate the image-data that is returned from the Camera (android.hardware.Camera.PictureCallback).
I have succeeded to manipulate the image to return a Grayscale of it which was my first goal.
Now I want to replace the entire image with an image loaded from the filesystem which I'm unsuccessful in doing. I've tried different methods, paths etc. but haven't managed to do it. I've never been able to find the file which I want to load.
The full path of the image file I want to load is according to Solid Explorer
Code:
/storage/emulated/0/input.png
What code should I use to load the filesystem image into a Bitmap?
Do I need to take any extra Camera parameters into account that says stuff about the image?
Do I need take file permissions into account?
I'm running an OPO on Lollipop 5.0.2 / Cyanogen OS 12.0 / Xposed 67
This is the code I've used to create the Grayscale example:
Code:
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.ColorMatrix;
import android.graphics.ColorMatrixColorFilter;
import android.graphics.Paint;
import android.os.Environment;
import java.io.ByteArrayOutputStream;
import java.io.File;
import static de.robv.android.xposed.XposedHelpers.findAndHookMethod;
import de.robv.android.xposed.IXposedHookLoadPackage;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.XC_MethodHook;
import de.robv.android.xposed.callbacks.XC_LoadPackage.LoadPackageParam;
public class CamHook implements IXposedHookLoadPackage {
public void handleLoadPackage(final LoadPackageParam lpparam) throws Throwable {
XposedBridge.log("Loaded app: " + lpparam.packageName);
if (!lpparam.packageName.equals("somepackage.somewhere.app"))
return;
XposedBridge.log("CamHook: We're here!");
findAndHookMethod("somepackage.somewhere.app.NewPhotoFragment$3$1", lpparam.classLoader, "onPictureTaken", "byte[]", "android.hardware.Camera", new XC_MethodHook() {
@Override
protected void beforeHookedMethod(MethodHookParam param) throws Throwable {
XposedBridge.log("CamHook: before picture taken");
XposedBridge.log("CamHook: byteLength " + ((byte[]) (param.args)[0]).length);
byte[] bitmapdata = ((byte[]) (param.args)[0]);
Bitmap bitmap = BitmapFactory.decodeByteArray(bitmapdata, 0, bitmapdata.length);
XposedBridge.log("CamHook: StorageState: " + Environment.getExternalStorageState());
XposedBridge.log("CamHook: StoragePath: " + Environment.getExternalStorageDirectory().getAbsolutePath());
XposedBridge.log("CamHook: StoragePathEnv: " + System.getenv("EXTERNAL_STORAGE"));
//Bitmap bitmap = BitmapFactory.decodeFile(Environment.getExternalStorageDirectory().getAbsolutePath() + "/input.jpg");
XposedBridge.log("CamHook: Bitmap is null: " + (bitmap == null));
bitmap = toGrayscale(bitmap);
ByteArrayOutputStream blob = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 0, blob);
param.args[0] = blob.toByteArray();
}
/*@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
// this will be called after the clock was updated by the original method
}*/
});
}
public Bitmap toGrayscale(Bitmap bmpOriginal)
{
int width, height;
height = bmpOriginal.getHeight();
width = bmpOriginal.getWidth();
Bitmap bmpGrayscale = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
Canvas c = new Canvas(bmpGrayscale);
Paint paint = new Paint();
ColorMatrix cm = new ColorMatrix();
cm.setSaturation(0);
ColorMatrixColorFilter f = new ColorMatrixColorFilter(cm);
paint.setColorFilter(f);
c.drawBitmap(bmpOriginal, 0, 0, paint);
return bmpGrayscale;
}
}
Does this mean it's working? App settings and YouTube adaway seem to work. But I know app settings can work without xposed
Did you get this to work?
Hi,
I found your thread. Did you ever get this to work?
Kind regards!
Hello did it work out for you? I am also looking into similar thing.
سلام
Related
Code:
public class MainActivity extends Activity implements SensorEventListener{
final String tag = "myLogs";
SensorManager sm = null;
Sensor lightSensor;
float lightQuantity;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
sm = (SensorManager) getSystemService(SENSOR_SERVICE);
lightSensor = sm.getDefaultSensor(Sensor.TYPE_LIGHT);
if(lightSensor == null)
Log.d(tag, "no sensor:(");
else
Log.d(tag, "GOT IT!");
}
@Override
protected void onResume() {
super.onResume();
sm.registerListener((SensorEventListener)this, lightSensor, SensorManager.SENSOR_DELAY_NORMAL);
}
@Override
protected void onStop() {
sm.unregisterListener((SensorEventListener)this);
super.onStop();
}
public void onAccuracyChanged(Sensor sensor, int accuracy) {
Log.d(tag,"onAccuracyChanged: " + sensor.getType() + ", accuracy: " + accuracy);
}
public void onSensorChanged(SensorEvent event) {
lightQuantity = event.values[0];
Log.d(tag,"onSensorChanged: " + event.sensor.getType() + ", result: " + lightQuantity);
}
}
cant reach the light sensor stats with this code
"no sensor" message always. What am i doung wrong?
You're not doing anything wrong. The problem is that Xperia doesn't have the sensor implemented in a standard Android way through drivers.
There's only a proprietary implementation which can be used through reading the kernel variables as detailed below.
The path to your sensor is "/sys/class/leds/lcd-backlight/als/value"
You can read it with the following code:
Code:
InputStream is = new FileInputStream(sensorPath);
InputStreamReader ir = new InputStreamReader(is);
char[] buf = new char[20];
int siz = ir.read(buf, 0, 20);
if (siz > 0)
{
float sensor = Float.parseFloat(String.copyValueOf(buf, 0, siz).replaceAll(",", "."));
}
is.close();
thank u once more)
Best all,
A while ago I tried to make a simple application which can export all my smses and mmses to my local database server. It runs quite smoothly but I can't manage to get the correct mms body data. It seems that about 5% of the exported body data(for example a sent picture in jpeg format) is different from the original jpeg picture/body data: the exported picture data can't be viewed, it is corrupt.
I suspect the method of exporting the data must be changed from string to binary, but I don't know exactly how to proceed.
I'm using C# 2008 in combination with the MAPIdotnet library, and my target device is a HTC HD Mini with Windows Mobile 6.5 professional.
The part of my code where it's going wrong:
Code:
ASCIIEncoding asen = new ASCIIEncoding();
byte[] ba = asen.GetBytes(s);
bw.Write(ba);
bw.Close();
fs.Close();
if (messages[msgID].Body != null)
{
FileStream fs2 = File.Create("\\Opslagkaart\\Debug\\body_" + Convert.ToString(msgID) + ".dat");
BinaryWriter bw2 = new BinaryWriter(fs2);
System.Text.UnicodeEncoding enc = new System.Text.UnicodeEncoding();
byte[] file = enc.GetBytes(messages[msgID].Body);
//bw2.Write(messages[msgID].Body);
bw2.Write(file);
bw2.Close();
fs2.Close();
}
In combination with MAPIdotnet's code:
Code:
public string Body
{
get
{
IStreamChar s = (IStreamChar)this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0);
if (s == null)
return "";
IntPtr p = Marshal.AllocHGlobal(4);
char[] b = new char[3];
StringBuilder str = new StringBuilder();
int c, len = b.Length * 2;
do
{
s.Read(b, len, p);
c = Marshal.ReadInt32(p);
str.Append(new string(b, 0, c / 2));
}
while (c >= len);
Marshal.FreeHGlobal(p);
return str.ToString();
}
}
Can somebody give a hint of how to proceed?
Thanks,
I suddenly got some more inspiration and, with help from google, I've managed to correctly retrieve the binary jpeg attachments of two of my mmses.
The code part of my program:
Code:
//if (messages[msgID].BodyBinary.Length>0)
//{
FileStream fs2 = File.Create("\\Opslagkaart\\Debug\\body_" + Convert.ToString(msgID) + ".dat");
BinaryWriter bw2 = new BinaryWriter(fs2);
bw2.Write(messages[msgID].BodyBinary);
bw2.Close();
fs2.Close();
//}
The code part of the customized MAPIdotnet:
Code:
private static IntPtr ReadBuffer;
static int Read(OpenNETCF.Runtime.InteropServices.ComTypes.IStream strm, byte[] buffer)
{
if (ReadBuffer == IntPtr.Zero) ReadBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)));
try
{
strm.Read(buffer, buffer.Length, ReadBuffer);
}
catch (NullReferenceException e)
{
//do nothing
}
return Marshal.ReadInt32(ReadBuffer);
}
public byte[] BodyBinary
{
get
{
int buffsize = 1024*1024*2; /* If mms body is bigger than 2MB we have a problem here */
byte[] buffer = new byte[buffsize];
Read(this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0), buffer);
byte[] data = buffer;//ms.ToArray();
Marshal.FreeCoTaskMem(ReadBuffer);
return data;
}
}
But now ALL bodies are saved as 2MB files.. including the empty ones from for example a sms. And not all mms bodies are of the max size of 2mb. My carrier/phone supports up to 1MB. Perhaps I need to get some 'dynamic size' buffer instead of the fixed one. Does anyone have an idea on how to determine the size of the
this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0)
Click to expand...
Click to collapse
stream ?
I've solved all my problems by means of the following code (for mapidotnet):
Code:
private static IntPtr ReadBuffer;
static int Read(OpenNETCF.Runtime.InteropServices.ComTypes.IStream strm, byte[] buffer)
{
int returnvalue = 0;
if (ReadBuffer == IntPtr.Zero) ReadBuffer = Marshal.AllocCoTaskMem(Marshal.SizeOf(typeof(int)));
try
{
strm.Read(buffer, buffer.Length, ReadBuffer);
returnvalue = Marshal.ReadInt32(ReadBuffer);
}
catch (NullReferenceException e)
{
returnvalue = 0;
}
return returnvalue;
}
public byte[] BodyBinary
{
get
{
int newdatasize = 0;
int buffsize = 1024*1024*3; /* If mms body is bigger than 3MB we have a problem here */
byte[] buffer = new byte[buffsize];
newdatasize = Read(this.msg.OpenProperty(cemapi.PropTags.PR_BODY, 0), buffer);
if (newdatasize < 0) { newdatasize = 0; }
byte[] data = new byte[newdatasize];
Buffer.BlockCopy(buffer, 0, data, 0, newdatasize);
Marshal.FreeCoTaskMem(ReadBuffer);
return data;
}
}
Now all is working fine and the exported files are of their own real size. I'm sure the above code can be optimized but it's working good now.
Hello, I am trying to hook a method and use the hooked app's resources in it, but I keep getting an error. Can you please have a look?
Code:
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) && (lpparam.packageName.contains("android.keyguard") || lpparam.packageName.contains("com.android.systemui"))) {
Class<?> KeyguardHostView = XposedHelpers.findClass("com.android.keyguard.KeyguardSecurityContainer",lpparam.classLoader);
findAndHookMethod(KeyguardHostView, "showSecurityScreen", "com.android.keyguard.KeyguardSecurityModel$SecurityMode", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Context ctx = ((FrameLayout) param.thisObject).getContext();
mStartTranslation = ctx.getResources().getDimensionPixelOffset(R.dimen.appear_y_translation_start) * translationScaleFactor;
}); }}
The relevant source for the hooked method is here https://github.com/temasek/android_...droid/keyguard/KeyguardSecurityContainer.java
Thank you for your time.
Rijul.A said:
Hello, I am trying to hook a method and use the hooked app's resources in it, but I keep getting an error. Can you please have a look?
Code:
public void handleLoadPackage(LoadPackageParam lpparam) throws Throwable {
if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) && (lpparam.packageName.contains("android.keyguard") || lpparam.packageName.contains("com.android.systemui"))) {
Class<?> KeyguardHostView = XposedHelpers.findClass("com.android.keyguard.KeyguardSecurityContainer",lpparam.classLoader);
findAndHookMethod(KeyguardHostView, "showSecurityScreen", "com.android.keyguard.KeyguardSecurityModel$SecurityMode", new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
Context ctx = ((FrameLayout) param.thisObject).getContext();
mStartTranslation = ctx.getResources().getDimensionPixelOffset(R.dimen.appear_y_translation_start) * translationScaleFactor;
}); }}
The relevant source for the hooked method is here https://github.com/temasek/android_...droid/keyguard/KeyguardSecurityContainer.java
Thank you for your time.
Click to expand...
Click to collapse
Depends on whether R.dimen.appear_y_translation_start is part of your module, or part of hooked package.
If it is part of hooked package resources you need to get it within hooked package context using proper identifier;
you cannot use identifier of resource you put in your module resources because it's completely different resource with different ID.
Example:
Code:
int resId = ctx.getResources().getIdentifier("appear_y_translation_start", "dimen", lpparam.packageName);
mStartTranslation = ctx.getResources().getDimensionPixelOffset(resId) * translationScaleFactor;
If this resource is part of your xposed module package, then you have to create package context using original context so you can get your module resources
which inherit proper display metrics from original package resources.
Code:
Context moduleContext = ctx.createPackageContext(myModulePackageName, Context.CONTEXT_IGNORE_SECURITY);
mStartTranslation = moduleContext.getResources().getDimensionPixelOffset(R.dimen.appear_y_translation_start) * translationScaleFactor;
C3C076 said:
Depends on whether R.dimen.appear_y_translation_start is part of your module, or part of hooked package.
If it is part of hooked package resources you need to get it within hooked package context using proper identifier;
you cannot use identifier of resource you put in your module resources because it's completely different resource with different ID.
Example:
Code:
int resId = ctx.getResources().getIdentifier("appear_y_translation_start", "dimen", lpparam.packageName);
mStartTranslation = ctx.getResources().getDimensionPixelOffset(resId) * translationScaleFactor;
If this resource is part of your xposed module package, then you have to create package context using original context so you can get your module resources
which inherit proper display metrics from original package resources.
Code:
Context moduleContext = ctx.createPackageContext(myModulePackageName, Context.CONTEXT_IGNORE_SECURITY);
mStartTranslation = moduleContext.getResources().getDimensionPixelOffset(R.dimen.appear_y_translation_start) * translationScaleFactor;
Click to expand...
Click to collapse
Thanks, that works very well. Can you please also explain to me how I can retrieve value of attribute resources (I think that's what they are called) from the hooked package resources?
Code:
android:textColor="?android:attr/textColorSecondary"
I want to get this colour (as used in XML) so that I can do it in code
Code:
mEmergencyButton.setTextColor(color)
In case someone is looking for a solution to this
Code:
TypedValue outValue = new TypedValue();
mContext.getTheme().resolveAttribute(android.R.attr.textColorSecondary, outValue, true);
int[] textSizeAttr = new int[] {android.R.attr.textColorSecondary};
TypedArray a = context.obtainStyledAttributes(outValue.data, textSizeAttr);
int textColor = a.getColor(0, -1);
a.recycle();
mEmergencyButton.setTextColor(textColor);
mContext.getTheme().resolveAttribute(android.R.attr.selectableItemBackground, outValue, true);
mEmergencyButton.setBackgroundResource(outValue.resourceId);
Hello friends!
I"m trying to build xposed module for educational purposes.
I want the module to:
1. Change the navigation bar color to green - this one works OK.
2. Change the navigation bar icons to custom icons i provide from my drawable resources - this one partially works, as described below.
The "home" button is changed, but the "recent apps" and "back" buttons didn't. Please see picture attached.
Can some one tell me why i can change the "home" button but not the "recent apps" and "back" buttons?
Any suggestion how to fix this?
module code:
Code:
import android.content.Context;
import android.content.res.XModuleResources;
import de.robv.android.xposed.IXposedHookInitPackageResources;
import de.robv.android.xposed.IXposedHookZygoteInit;
import de.robv.android.xposed.XposedBridge;
import de.robv.android.xposed.callbacks.XC_InitPackageResources.InitPackageResourcesParam;
import de.robv.android.xposed.callbacks.XC_LayoutInflated;
import android.graphics.Color;
import android.view.View;
import android.widget.ImageView;
import android.widget.LinearLayout;
public class TweakNavigationBar implements IXposedHookZygoteInit, IXposedHookInitPackageResources {
private static String MODULE_PATH = null;
@Override
public void initZygote(StartupParam startupParam) throws Throwable {
MODULE_PATH = startupParam.modulePath;
}
@Override
public void handleInitPackageResources(InitPackageResourcesParam resparam) throws Throwable {
if (!resparam.packageName.equals("com.android.systemui"))
return;
resparam.res.hookLayout("com.android.systemui", "layout", "navigation_bar", new XC_LayoutInflated() {
@Override
public void handleLayoutInflated(LayoutInflatedParam liparam) throws Throwable {
XModuleResources modRes = XModuleResources.createInstance(MODULE_PATH, liparam.res);
LinearLayout NavigationButtonsLayout = (LinearLayout) liparam.view.findViewById(
liparam.res.getIdentifier("nav_buttons", "id", "com.android.systemui"));
NavigationButtonsLayout.setBackgroundColor(Color.GREEN);
Context mContext = NavigationButtonsLayout.getContext();
ImageView backButton = (ImageView) liparam.view.findViewById(liparam.res.getIdentifier("back", "id", "com.android.systemui"));
ImageView homeButton = (ImageView) liparam.view.findViewById(liparam.res.getIdentifier("home", "id", "com.android.systemui"));
ImageView recentButton = (ImageView) liparam.view.findViewById(liparam.res.getIdentifier("recent_apps", "id", "com.android.systemui"));
//this also didn't work
//ImageView backButton = (ImageView) NavigationButtonsLayout.getChildAt(2);
//ImageView homeButton = (ImageView) NavigationButtonsLayout.getChildAt(3);
//ImageView recentButton = (ImageView) NavigationButtonsLayout.getChildAt(4);
recentButton.setImageDrawable(modRes.getDrawable(R.drawable.blue_button,null)); // didn't work!
homeButton.setImageDrawable(modRes.getDrawable(R.drawable.red_button,null)); // WORKS!
backButton.setImageDrawable(modRes.getDrawable(R.drawable,yellow_button,null)); // didn't work!
XposedBridge.log("start scan:");
for(int i=0; i< NavigationButtonsLayout.getChildCount() ; i++) {
View viewChild = (View) NavigationButtonsLayout.getChildAt(i);
XposedBridge.log(viewChild.toString());
if(viewChild instanceof ImageView)
XposedBridge.log("Child At " + i + " is instanceof ImageView" ) ;
}
}
});
}
}
Use this:
resparam.res.setReplacement(SYSTEM_UI, "drawable", "ic_sysbar_back_ime", modRes.fwd(R.drawable.n_back_down));
resparam.res.setReplacement(SYSTEM_UI, "drawable", "ic_sysbar_recent", modRes.fwd(R.drawable.n_recents));
resparam.res.setReplacement(SYSTEM_UI, "drawable", "ic_sysbar_back", modRes.fwd(R.drawable.n_back));
Note: SYSTEM_UI="com.android.systemui"
Using my method, i wasnt able to change the home button. But using your method, it did!
Thanks man!
Hello,
Iam working on a XposedModule and I need to get a variable from an other class. I have access to this class and I can access the global variables from this class but I can not access a variable which is only available in a method.
using:
Code:
Class<?> ProfileInfoClass = XposedHelpers.findClass("com.hi",lpparam.classLoader);
XposedBridge.hookAllMethods(ProfileInfoClass,"hie",new XC_MethodHook() {
@Override
protected void afterHookedMethod(MethodHookParam param) throws Throwable {
super.afterHookedMethod(param);
String s = (String)XposedHelpers.getObjectField(param.thisObject,"hello2"); //not found
}
});
with this class:
Code:
public class hi(){
String hello = "hello"; //This variable I can get
public void hie(){
String hello2 = "hi"; //This Variable I can not get using XposedHelpers.getObjectField(param.thisObject,"hello2");
}
}
Is there an other way to access variables inner Mehtods?
Thanks. Jojii
Nope, you can't.