Hello XDA, i have been looking for a way to root the ZTE Blade Apex2 from Orange Spain (also known as Orange Hi 4G), and i found some interesting things about how the system manages the partitions and how the OTA update is done.
Packed inside Recovery.img in /etc/recovery.fstab we can read this:
Code:
# mount point fstype device [device2] [length=]
/dev/block/platform/msm_sdcc.1/by-name/system /system ext4 ro,barrier=1 wait
/dev/block/platform/msm_sdcc.1/by-name/cache /cache ext4 noatime,nosuid,nodev,barrier=1,data=ordered wait,check
As you can see, the property BARRIER is enabled on all the mountpoints "interesting" to be accesed, so we CANT remount this mountpoints.
So i changed my mind to look for another way to try to make the trick, and unexpectedly, i found a nice glitch on the way how the official updater does the ota update process.
I decrypted the app itself from the decompyleandroid web, and got surprised.
The first thing called my attention is that the reboot on recovery to install the ota update, DONT check the signature of the file, its done by the otaupdater itself, so, we can try a replace file trick to change the target file.
Another interesting thing i found, is in the otaupdater, found this interesting piece of code:
Code:
[HIDE]package com.orange.authentication.utunneling.ttg;
import java.io.IOException;
import java.io.InputStream;
import java.nio.ByteBuffer;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
public class TtgX509TrustManager
implements X509TrustManager
{
private static final String KEYSTORE = "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";
[B][I][SIZE="3"][COLOR="Red"]private static final char PASSPHRASE[] = "orange".toCharArray();[/COLOR][/SIZE][/I][/B]
private X509TrustManager mTrustManager;
public TtgX509TrustManager(boolean flag)
throws GeneralSecurityException, IOException
{
if (flag)
{
KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
keystore.load(newInputStream(decodeBase64("AAAAAQAAABSR52UCnjiSFiwLKyzthZxY4sJ0ZQAABdEBAAh2ZXJpc2lnbgAAASw2S2EsAAAAAAAFWC41MDkAAAMGMIIDAjCCAmsCEH3Z/gfPqB63EHln+6eJNMYwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDMXtERXVxp0KvTuWpMmR9ZmDCOFoUgRm1HP9SFIIThbbP4pO0M8RcPO/mn+SXXwc+EY/J8Y8+iR/LGWzOOZEAEaMGAuWQcRXfH2G71lSk8UOg013gfqLptQ5GVj0VXXn7F+8qkBOvqlzdUMG+7AUcyM83cV5tkaWH4mx0ciU9cZwIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFFNzb5cy5gZnBWyATl4Lk0PZ3BwmcYQWpSkU01UbSuvDV1Ai2TT1+7eVmGSX6bEHRBhNtMsJzzoKQm5EWR0zLVznxxIqbxhAe7iF6YM40AIOw7n60RzKprxaZLvcRTDOaxxp5EJb+RxBrO6WVcmeQD2+A2iMzAo1KpYoJ2daZH9AQAKb3JhbmdlX3R0ZwAAASw2S6sfAAAAAAAFWC41MDkAAAOaMIIDljCCAv+gAwIBAgIJAOzGENAox4zdMA0GCSqGSIb3DQEBBQUAMIGPMQswCQYDVQQGEwJGUjEWMBQGA1UECBMNSWxlIGRlIEZyYW5jZTEOMAwGA1UEBxMFUGFyaXMxFzAVBgNVBAoTDkZyYW5jZSBUZWxlY29tMSgwJgYDVQQLEx9GVC1PRi1EVEYtREVYLURFQ0ktRUVEQVRBLU9TQ1BTMRUwEwYDVQQDEwxPcmFuZ2VUVEctQ0EwHhcNMTAxMTEwMTAzNDQ5WhcNMzAxMTA1MTAzNDQ5WjCBjzELMAkGA1UEBhMCRlIxFjAUBgNVBAgTDUlsZSBkZSBGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRcwFQYDVQQKEw5GcmFuY2UgVGVsZWNvbTEoMCYGA1UECxMfRlQtT0YtRFRGLURFWC1ERUNJLUVFREFUQS1PU0NQUzEVMBMGA1UEAxMMT3JhbmdlVFRHLUNBMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC+MWWiupCgPdKl2jH2dl2HZ5VzzZPc+T/teetDqdme17tDAbzEEKc6bf/WB3bUY4qgS2sbB8Gz/jMekfmJ3tLpW93WOwpnmaGAY0+ZdZylacejycAdOeiPS8bq9zUlfYGPi0MvaPcAoSO75hkV/14xLLKjGY7aCNMC4Ws1+0PqSQIDAQABo4H3MIH0MB0GA1UdDgQWBBTbMtaQXxFEPq1PYFCzwRirTy6+qzCBxAYDVR0jBIG8MIG5gBTbMtaQXxFEPq1PYFCzwRirTy6+q6GBlaSBkjCBjzELMAkGA1UEBhMCRlIxFjAUBgNVBAgTDUlsZSBkZSBGcmFuY2UxDjAMBgNVBAcTBVBhcmlzMRcwFQYDVQQKEw5GcmFuY2UgVGVsZWNvbTEoMCYGA1UECxMfRlQtT0YtRFRGLURFWC1ERUNJLUVFREFUQS1PU0NQUzEVMBMGA1UEAxMMT3JhbmdlVFRHLUNBggkA7MYQ0CjHjN0wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOBgQBuShubIhCowVw5e/Zx4O/2es78YXMJBXVQ/7bhM4sGZ6HAsahIXg0l6aP8xROGsfofetz+9WjRMyeUMzsovcdNnNR/ge0nr5BQb7Ef/4N6DNbd6t0u1InNSRIXemwPI/77ggVf8XgW24JgfSb5CwqSq4adfev5K4IUBeQeQmnNMQEAD3ZlcmlzaWduX3NlcnZlcgAAASxVM/4GAAAAAAAFWC41MDkAAAYwMIIGLDCCBZWgAwIBAgIQbk/6s8XmacTRZ8mSq+hYxDANBgkqhkiG9w0BAQUFADCBwTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTwwOgYDVQQLEzNDbGFzcyAzIFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5IC0gRzIxOjA4BgNVBAsTMShjKSAxOTk4IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNlIG9ubHkxHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdvcmswHhcNMDkwMzI1MDAwMDAwWhcNMTkwMzI0MjM1OTU5WjCBtTELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrMTswOQYDVQQLEzJUZXJtcyBvZiB1c2UgYXQgaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL3JwYSAoYykwOTEvMC0GA1UEAxMmVmVyaVNpZ24gQ2xhc3MgMyBTZWN1cmUgU2VydmVyIENBIC0gRzIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDUVo9XOzcopkBj0pXVBXTatRlqltZxVy/iwDSMoJWzjOE3JPMu7UNFBY6J1/raSrX4Po1Ox/lJUEU3QJ90qqBRVWHxYISJpZ6AjS+wIapFgsTPtBR/RxUgKIKwaBLArlwH1/ZZzMtiVlxNSf8miKtUUTovStoOmOKJcrn892g8xB85essXgfMMrQ/cYWIbEAsEHikYcV5iy0PevjG6cQIZTiapUdqMZGkD3pz9ff17Ybz8hHyIXLTDe+1fK0YS8f0AAZqLW+mjBS6PLlve8xt4+GaRCMBeztWwNsrUqHugffkwer/43RlRKyC6/qfPoU6wZ/WAqiuDLtKOVImOHikLAgMBAAGjggKpMIICpTA0BggrBgEFBQcBAQQoMCYwJAYIKwYBBQUHMAGGGGh0dHA6Ly9vY3NwLnZlcmlzaWduLmNvbTASBgNVHRMBAf8ECDAGAQH/AgEAMHAGA1UdIARpMGcwZQYLYIZIAYb4RQEHFwMwVjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cudmVyaXNpZ24uY29tL2NwczAqBggrBgEFBQcCAjAeGhxodHRwczovL3d3dy52ZXJpc2lnbi5jb20vcnBhMDQGA1UdHwQtMCswKaAnoCWGI2h0dHA6Ly9jcmwudmVyaXNpZ24uY29tL3BjYTMtZzIuY3JsMA4GA1UdDwEB/wQEAwIBBjBtBggrBgEFBQcBDARhMF+hXaBbMFkwVzBVFglpbWFnZS9naWYwITAfMAcGBSsOAwIaBBSP5dMahqyNjmvDz4Bq1EgYLHsZLjAlFiNodHRwOi8vbG9nby52ZXJpc2lnbi5jb20vdnNsb2dvLmdpZjApBgNVHREEIjAgpB4wHDEaMBgGA1UEAxMRQ2xhc3MzQ0EyMDQ4LTEtNTIwHQYDVR0OBBYEFKXvCxHOwEEDo0plkEiyHOBXLX1HMIHnBgNVHSMEgd8wgdyhgcekgcQwgcExCzAJBgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMyBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2lnbiwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVzdCBOZXR3b3JrghB92f4Hz6getxB5Z/uniTTGMA0GCSqGSIb3DQEBBQUAA4GBAGN0Lz1Tqi+X7CYRZhr+8d5BJxnSf9jBHPniOFY6H5CuOcUgdav4bC1nHynCIdcUiGNLsJsnY5H48KMBJLb7j+M9AgtvVP7UzNvWhb98lR5eYhHB2QmcQrmy1KotmDojYMyimvFu6M+O0Ro8XhnF15s1sAIjJOUFuNWI4+D6ufRfAF0Slrj4O266ePon5MC54zEX3hju")), PASSPHRASE);
TrustManagerFactory trustmanagerfactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
trustmanagerfactory.init(keystore);
javax.net.ssl.TrustManager atrustmanager[] = trustmanagerfactory.getTrustManagers();
if (atrustmanager == null || atrustmanager.length != 1 || !(atrustmanager[0] instanceof X509TrustManager))
{
throw new IllegalArgumentException("Invalid keystore");
}
mTrustManager = (X509TrustManager)atrustmanager[0];
}
}
private static ByteBuffer decodeBase64(String s)
{
ByteBuffer bytebuffer = ByteBuffer.allocate((6 * s.length()) / 8);
int i = 0;
int j = 0;
for (int k = 0; k < s.length(); k++)
{
int l = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".indexOf(s.charAt(k));
if (l == -1)
{
continue;
}
i = l | i << 6;
for (j += 6; j >= 8;)
{
j -= 8;
bytebuffer.put((byte)(i >> j));
}
}
bytebuffer.flip();
return bytebuffer;
}
private static InputStream newInputStream(ByteBuffer bytebuffer)
{
return new InputStream(bytebuffer) {
final ByteBuffer val$buffer;
public int read()
throws IOException
{
this;
JVM INSTR monitorenter ;
boolean flag = buffer.hasRemaining();
if (flag) goto _L2; else goto _L1
_L1:
byte byte1 = -1;
_L4:
this;
JVM INSTR monitorexit ;
return byte1;
_L2:
byte byte0 = buffer.get();
byte1 = byte0;
if (true) goto _L4; else goto _L3
_L3:
Exception exception;
exception;
throw exception;
}
public int read(byte abyte0[], int i, int j)
throws IOException
{
this;
JVM INSTR monitorenter ;
int k;
k = Math.min(j, buffer.remaining());
buffer.get(abyte0, i, k);
this;
JVM INSTR monitorexit ;
return k;
Exception exception;
exception;
throw exception;
}
{
buffer = bytebuffer;
super();
}
};
}
public void checkClientTrusted(X509Certificate ax509certificate[], String s)
throws CertificateException
{
if (mTrustManager != null)
{
mTrustManager.checkClientTrusted(ax509certificate, s);
}
}
public void checkServerTrusted(X509Certificate ax509certificate[], String s)
throws CertificateException
{
if (mTrustManager != null)
{
mTrustManager.checkServerTrusted(ax509certificate, s);
}
}
public X509Certificate[] getAcceptedIssuers()
{
if (mTrustManager != null)
{
return mTrustManager.getAcceptedIssuers();
} else
{
return new X509Certificate[0];
}
}
}[/HIDE]
Orange is so kind to provide us not only the certificate, but the key itself
Im uploading the sources of the otaupdater application that Orange is using on our Blade Apex2 aka Orange Hi 4G.
P.S. This phone allows us to upgrade and downgrade all the times needed, so dont hesitate to ask, just booting on recovery menu lets me flash previous firmware versions.
Hopes any developer find some time to take a look on it, im ready to test anything.
Related
Hi there,
I am writing an app and for one of the features I need the firmware build number.
I know I can get the firmware version(like 4.1.1) with android.os.build but I need the build number of a rom(like "Rom version 1.0") thats stored in build.prop. I know I can parse the whole build.prop file and extract the 1 string of information but is there another way to get is faster and that it doesnt require root to use?
Grtz,
Thirith
Solved it
I solved my own question
Here is how I did it(in case somebody wants to achieve the same thing):
Code:
TextView tv = (TextView)findViewById(R.id.text1);
String input = "getprop |awk -F : '/build.display.id/ { print $2 }'";
execCommandLine(input, tv);
void execCommandLine(String command, TextView tv)
{
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
// Running the Script
try
{
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(command);
osw.flush();
osw.close();
}
// If return error
catch (IOException ex)
{
// Log error
Log.e("execCommandLine()", "Command resulted in an IO Exception: " + command);
return;
}
// Try to close the process
finally
{
if (osw != null)
{
try
{
osw.close();
}
catch (IOException e){}
}
}
try
{
proc.waitFor();
}
catch (InterruptedException e){}
// Display on screen if error
if (proc.exitValue() != 0)
{
Log.e("execCommandLine()", "Command returned error: " + command + "\n Exit code: " + proc.exitValue());
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage(command + "\nWas not executed sucessfully!");
builder.setNeutralButton("OK", null);
AlertDialog dialog = builder.create();
dialog.setTitle("Script Error");
dialog.show();
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
try {
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String exit = output.toString();
if(exit != null && exit.length() == 0) {
exit = "Command executed Successfully but no output was generated";
}
tv.setText(exit);
}
Hi, thanks for making your code public!
Just got an error when trying your code into my app.
Line
Code:
execCommandLine(input, tv);
runs into this error:
Multiple markers at this line
- input cannot be resolved to a type
- Return type for the method is missing
- Syntax error on token ",", delete this
token
Click to expand...
Click to collapse
How do I fix it?
Ok, did a mistake with integrating the code. My whole activity:
Code:
package de.yanniks.cm_updatechecker;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import de.yanniks.cm_updatechecker.R;
import android.app.Activity;
import android.app.AlertDialog;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;
public class UpdateChecker extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.updatecheck);
TextView tv = (TextView)findViewById(R.id.installedversion);
String input = "getprop |awk -F : '/build.display.id/ { print $2 }'";
execCommandLine(input, tv);}
void execCommandLine(String command, TextView tv)
{
Runtime runtime = Runtime.getRuntime();
Process proc = null;
OutputStreamWriter osw = null;
// Running the Script
try
{
proc = runtime.exec("su");
osw = new OutputStreamWriter(proc.getOutputStream());
osw.write(command);
osw.flush();
osw.close();
}
// If return error
catch (IOException ex)
{
// Log error
Log.e("execCommandLine()", "Command resulted in an IO Exception: " + command);
return;
}
// Try to close the process
finally
{
if (osw != null)
{
try
{
osw.close();
}
catch (IOException e){}
}
}
try
{
proc.waitFor();
}
catch (InterruptedException e){}
// Display on screen if error
if (proc.exitValue() != 0)
{
Log.e("execCommandLine()", "Command returned error: " + command + "\n Exit code: " + proc.exitValue());
AlertDialog.Builder builder = new AlertDialog.Builder(UpdateChecker.this);
builder.setMessage(command + "\nWas not executed sucessfully!");
builder.setNeutralButton("OK", null);
AlertDialog dialog = builder.create();
dialog.setTitle("Script Error");
dialog.show();
}
BufferedReader reader = new BufferedReader(
new InputStreamReader(proc.getInputStream()));
int read;
char[] buffer = new char[4096];
StringBuffer output = new StringBuffer();
try {
while ((read = reader.read(buffer)) > 0) {
output.append(buffer, 0, read);
}
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
String exit = output.toString();
if(exit != null && exit.length() == 0) {
exit = "Command executed Successfully but no output was generated";
}
tv.setText(exit);
}
}
A better solution is to use my SystemProperties.get("build.display.id") directly instead of forking a native binary.
Code:
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.ByteOrder;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
public class SystemProperties {
public static final int PROP_NAME_MAX= 32; // sic
public static final int PROP_VALUE_MAX= 92; // sic
public static final int PROP_AREA_MAGIC= 0x504f5250; // "PROP"
public static final int PROP_AREA_VERSION= 0x45434f76; // "vOCE" (API level 3..8 at least)
public static final String PROP_SERVICE_NAME= "property_service";
public static final String WORKSPACE= "ANDROID_PROPERTY_WORKSPACE";
// prop_area struct
public static final int PA_COUNT= 0;
public static final int PA_SERIAL= 4;
public static final int PA_MAGIC= 8;
public static final int PA_VERSION= 12;
public static final int PA_RESERVED= 16;
public static final int PA_TOC= 32;
public static final int PA_INFO_NAME= 0;
public static final int PA_INFO_SERIAL= PA_INFO_NAME+PROP_NAME_MAX;
public static final int PA_INFO_VALUE= PA_INFO_SERIAL+4;
private static MappedByteBuffer mMap= null;
private static boolean init() throws IllegalArgumentException,
SecurityException,
NoSuchFieldException,
IllegalAccessException,
IOException {
FileDescriptor fd;
MappedByteBuffer mbb= null;
String workspace= System.getenv(WORKSPACE);
if (workspace == null) {
throw new IllegalArgumentException(WORKSPACE + " not set");
}
String[] wsArray= workspace.split(",");
int osFd= 0;
int len= 0;
try {
osFd= new Integer(wsArray[0]);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e.getMessage());
}
try {
len= new Integer(wsArray[1]);
} catch (NumberFormatException e) {
throw new IllegalArgumentException(e.getMessage());
}
//Log.i(TAG, "Read fd " + Integer.toString(osFd) + " for " + len + " bytes.");
fd= new FileDescriptor();
Class<?> c= fd.getClass();
Field f= c.getDeclaredField("descriptor");
f.setAccessible(true);
f.setInt(fd, osFd);
FileInputStream in= new FileInputStream(fd);
FileChannel fc= in.getChannel();
mbb= fc.map(FileChannel.MapMode.READ_ONLY, 0, len);
mbb.order(ByteOrder.LITTLE_ENDIAN);
if (mbb.getInt(PA_MAGIC) != PROP_AREA_MAGIC) {
throw new IllegalArgumentException("Wrong kind of magic " + Integer.toString(mbb.getInt(PA_MAGIC), 16));
}
if (mbb.getInt(PA_VERSION) != PROP_AREA_VERSION) {
throw new IllegalArgumentException("Incorrect version " + Integer.toString(mbb.getInt(PA_VERSION), 16));
}
mMap= mbb;
return(true);
}
public static String get(String key) throws IllegalArgumentException,
SecurityException,
NoSuchFieldException,
IllegalAccessException,
IOException {
if (mMap == null) {
if (!init())
return(null);
}
int index= property_find(key);
//Log.i(TAG, "Found entry at " + Integer.toString(index));
if (index < 0)
return(null);
return(getString(index+PA_INFO_VALUE));
}
private static int property_find(String name) {
int count= mMap.getInt(PA_COUNT);
int tok= -1;
//Log.i(TAG, "Key " + name);
next: while(count-- > 0) {
tok++;
int entry= mMap.getInt(PA_TOC + tok*4);
//Log.i(TAG, "Entry " + tok + ": " + Integer.toString(entry, 16));
if ((entry >> 24) != name.length())
continue;
int index= (entry & 0xFFFFFF);
//Log.i(TAG, "Index " + index);
for (int i=0; i<name.length(); i++) {
//Log.i(TAG, "Cmp(" + entry + ":" + index + ":" + i + "): " + (char)(mbb.get(index+i)) + " -- " + name.charAt(i));
if ((char)(mMap.get(index+i)) != name.charAt(i)) {
continue next;
}
}
// found
return(index);
}
return(-1);
}
private static String getString(int index) {
byte b[]= new byte[PROP_VALUE_MAX];
int i= 0;
do {
b[i]= mMap.get(i+index);
} while (b[i++] != 0);
return(new String(b, 0, i-1));
}
}
Sorry 'bout the terrible indentation. Cut'n'paste isn't my code's best friend, obviously.
Hi Droid-expert
For stock bootanimation in JB, there is a single threaded animation process/class inside. If I'd like to implement the power-on sound/tune as well. What's the best programming scheme/model it could be?
So far, by my understanding, I did something in BootAnimation.cpp in the following:
Did I do wrong? The handset boots up, it shows the animation first, and then the sound is played.
However, in a normal AOS adb shell session, try to run bootanimation, and it works fine (I mean both animation and sound are played at the same time)
Does the init is multi-threaded?
Anthony
class PlayerListener: public MediaPlayerListener, public Thread
{
public:
PlayerListener(): Thread(false), mp(NULL) {}
~PlayerListener() { delete mp; mp = NULL; }
virtual void notify(int, int, int, const Parcel *) {}
virtual bool threadLoop();
virtual status_t readyToRun();
private:
MediaPlayer* mp;
};
// ----------------------------------------------------------------------
bool PlayerListener::threadLoop()
{
if (mp != NULL)
mp->start();
sleep(100);
requestExit();
return false;
}
status_t PlayerListener::readyToRun()
{
int index = 7;
audio_devices_t device;
bool r;
mp = new MediaPlayer();
mp->setListener(this);
if (mp->setDataSource(SYSTEM_BOOTANIMATION_SOUND_FILE, NULL) == NO_ERROR) {
mp->setAudioStreamType(AUDIO_STREAM_ENFORCED_AUDIBLE);
mp->prepare();
mp->setLooping(false);
}
// AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index);
device = AudioSystem::getDevicesForStream(AUDIO_STREAM_ENFORCED_AUDIBLE);
r = AudioSystem::setStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, index, device);
r = AudioSystem::getStreamVolumeIndex(AUDIO_STREAM_ENFORCED_AUDIBLE, &index, device);
if (index != 0) {
mp->seekTo(0);
// mp->start();
}
return NO_ERROR;
}
bool BootAnimation::threadLoop()
{
bool r;
sp<PlayerListener> player = new PlayerListener();
player->run("BootAnimatedMelody", PRIORITY_AUDIO);
if (mAndroidAnimation) {
r = android();
} else {
r = movie();
}
Hello Iv been developing my app for around 2 weeks now and Iv hit a bug were I'm getting a null pointer Exception error iv been going around and around in circles trying to figure out what I'm doing wrong but im completely new to programming iv posted my code below and if you have any idea what im doing wrong please tell me
mainActivity
package com.example.joelg.clapp;
import android.database.Cursor;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import java.util.ArrayList;
import android.widget.TextView;
public class MainActivity extends AppCompatActivity {
ListView lstJob;
IntDataBaseHelper myhelper = new IntDataBaseHelper(this);
ArrayAdapter<String> mAdapter;
@override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
/*create instance of db helper and jobs
Create the database (only if it doesn't exists)
does so by copying from the assets */
LoadJobList();
if (CopyDBFromAssets.createDataBase(this,IntDataBaseHelper.DB_TABLE)) {
// problem area
// Get the data from the database
lstJob = (ListView) findViewById(R.id.lstJob);
ArrayList<String> jobs = myhelper.getJobList();
for (String s : jobs) {
Log.d("JobList ", "Found Job " + s);
}
} else {
throw new RuntimeException("No Usable Database exists or was copied from the assets.");
}
}
// loads job to screen
public void LoadJobList() {
ArrayList<String> JobList = myhelper.getJobList();
if (mAdapter == null) {
mAdapter = new ArrayAdapter<>(this,R.layout.header,R.id.header);
mAdapter = new ArrayAdapter<>(this,R.layout.row,R.id.BtnComplete,JobList);
mAdapter = new ArrayAdapter<>(this, R.layout.row, R.id.Job_name,JobList);
lstJob.setAdapter(mAdapter);
} else
{
mAdapter.clear();
mAdapter.addAll(JobList);
mAdapter.notifyDataSetChanged();
}
}
}
// public void JobComplete(View view){
// View parent = (View)view.getParent();
// TextView taskTextView=(TextView)parent.findViewById(R.id.BtnComplete);
// Log.e("String",(String) taskTextView.getText());
//
this is My IntDatabaseHandler file
package com.example.joelg.clapp;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.database.sqlite.SQLiteOpenHelper;
import android.util.Log;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.iutputStream;
import java.util.ArrayList;
/**
* Created by joelg on 22/10/2017.
*/
public class IntDataBaseHelper extends SQLiteOpenHelper{
private static String DB_PATH ="/data/data/com.example.joelg.clapp/databases";
public static String DB_NAME = "JobList";
public static String DB_COLUMN = "jobNM";
public static String DB_TABLE = "job";
private static String DB_JOB_DETAILS = "jobDetails";
private static String DB_ISDONE = "jobIsDone";
public Context jobContext;
private SQLiteDatabase JobListDatabase;
/**
* constructor t
*/
public IntDataBaseHelper (Context context) {
super (context, DB_NAME,null, 1);
this.jobContext = context;
DB_PATH = jobContext.getDatabasePath(DB_NAME).getPath();
}
public void openDataBase() {
// open the database
String JobListPath = DB_PATH;
JobListDatabase = SQLiteDatabase.openDatabase(JobListPath,null,SQLiteDatabase.OPEN_READONLY);
}
// Getting Job Count
public ArrayList<String> getJobList() {
ArrayList<String> JobList = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(DB_TABLE,new String[]
{DB_COLUMN},null,null,null,null,null);
while(cursor.moveToNext()){
int index = cursor.getColumnIndex(DB_COLUMN);
JobList.add(cursor.getString(index));
}
cursor.close();
db.close();
return JobList;
}
// Gets the job state if it has been competed or not
public ArrayList<String> getIsDone() {
ArrayList<String> IsDone = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
Cursor cursor = db.query(DB_TABLE,new String[]{DB_ISDONE},null,null,null,null,null);
while(cursor.moveToNext()){
int index = cursor.getColumnIndex(DB_ISDONE);
IsDone.add(cursor.getString(index));
}
cursor.close();
db.close();
return IsDone;
}
@override
public synchronized void close(){
if(JobListDatabase !=null){
JobListDatabase.close();
super.close();
}
}
@override
public void onCreate(SQLiteDatabase db) {
}
@override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
CopyDBFromAssets
package com.example.joelg.clapp;
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteException;
import android.util.Log;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.iutputStream;
/**
* Created by joelg on 24/10/2017.
*/
public class CopyDBFromAssets {
boolean copied = false;
public static boolean createDataBase(Context context, String databasename) {
boolean copied = false;
boolean dbExist = checkDataBase(context, databasename);
if (!dbExist) {
// calling this method will create an empty database
// which will hopefully be overidden, if not then
// empty database will exist ?????????
//this.getReadableDatabase(); <<<<< NOTE Commented out as empty db with no tables is useless
if (!checkAssetExists(context, databasename, "")) {
Log.e("CREATEDB", "Error getting asset " + databasename);
} else {
return copyDataBase(context, databasename);
}
return false;
}
return true;
}
private static boolean checkAssetExists(Context context, String assetfile, String path) {
boolean rv = false; // assume asset file doesn't exist
String[] assetsfound = new String[]{};
// Get the list of assets at the given path
try {
assetsfound = context.getAssets().list(path);
} catch (IOException e) {
Log.e("CHECKASSET", "IO Exception when checking for the asset file." + e.getMessage());
return false;
}
// Check to see if the desired asset (passed assetfile) exists
for (String s : assetsfound) {
if (s.equals(assetfile)) {
rv = true;
break;
}
}
if (rv) {
Log.d("CHECKASSET", "Asset " + assetfile + "was found.");
} else {
String assetlist = "";
for (String s : assetsfound) {
assetlist = assetlist + " " + s;
}
Log.e("CHECKASSET", "Asset " + assetfile +
"could not be found. Assets that exists are:- " +
assetlist
);
}
// Asset not found lets try ignoring case
if (!rv) {
for (String s : assetsfound) {
if ((s.toLowerCase()).equals(assetfile.toLowerCase())) {
Log.e("CHECKASSET", "Found asset as " + assetfile +
" but looking for " + s +
", although they are similar the case is different."
);
}
}
}
return rv;
}
// check if database exists to avoid recopying it
private static boolean checkDataBase(Context context, String database) {
SQLiteDatabase checkDB = null;
String dbpath = context.getDatabasePath(database).getPath();
try {
checkDB = SQLiteDatabase.openDatabase(dbpath, null,
SQLiteDatabase.OPEN_READONLY);
} catch (SQLiteException e) {
// database doesnt exist yet
}
if (checkDB != null) {
checkDB.close();
}
return checkDB != null ? true : false;
}
// copies db from local assets file, were it can be accessed and handled
private static boolean copyDataBase(Context context, String databasename) {
InputStream asset;
OutputStream db;
int bytescopied = 0;
int length_read;
int buffersize = 16384;
int blockcount = 0;
boolean rv = false;
try {
asset = context.getAssets().open(databasename);
} catch (IOException e) {
Log.e("COPYDB",
"IO Error opening the asset " +
databasename +
". Error Message was " +
e.getMessage()
);
return false;
}
try {
db = new FileOutputStream(context.getDatabasePath(databasename).getPath());
} catch (IOException e) {
Log.e("COPYDB",
"IO Error opening the output file for the database with path " +
databasename +
". error Message was " +
e.getMessage()
);
try {
asset.close();
} catch (IOException e2) {
Log.e("COPYDB",
"IO Error closing the asset. Message was " + e2.getMessage()
);
}
return false;
}
byte[] buffer = new byte[buffersize];
try {
while ((length_read = asset.read(buffer)) > 0) {
db.write(buffer);
bytescopied = bytescopied + length_read;
blockcount++;
rv = true;
}
} catch (IOException e) {
Log.e("COPYDB",
"IO Error Copying Database. Bytes Copied = "
+ bytescopied +
" in " +
blockcount +
" blocks of " +
buffersize
);
}
Log.d("COPYDB", "Succesfully copied Database " + databasename + " from the assets." +
" Number of bytes copied = " + bytescopied +
" in " + blockcount + " blocks of length " + buffersize
);
try {
db.flush();
db.close();
asset.close();
} catch (IOException e) {
Log.e("COPYDB",
"IO Error flushing or closing Database or closing asset."
);
}
return rv;
}
}
Hello,
I'm trying to use Janus vulnerability to get root, and I pasted the file I modified below,
Really, most of the code doesn't matter but I pasted them anyway.
Is that code starting from "public static void copyDirectory" going to work, with copying /data/local/tmp/su to /system/bin/su ?
Any help is appreciated!
Code:
package com.android.calculator2;
import android.animation.Animator;
import android.animation.Animator.AnimatorListener;
import android.animation.AnimatorSet;
import android.animation.AnimatorSet.Builder;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.app.Activity;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.Bundle;
import android.support.v4.view.ViewPager;
import android.text.Editable;
import android.text.Editable.Factory;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.View.OnLongClickListener;
import android.view.ViewAnimationUtils;
import android.view.ViewGroupOverlay;
import android.view.Window;
import android.view.animation.AccelerateDecelerateInterpolator;
import android.widget.Button;
import android.widget.TextView;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
public class Calculator
extends Activity
implements View.OnLongClickListener, CalculatorEditText.OnTextSizeChangeListener, CalculatorExpressionEvaluator.EvaluateCallback
{
private static final String a = Calculator.class.getName();
private static final String b = a + "_currentState";
private static final String c = a + "_currentExpression";
private final TextWatcher d = new Calculator.1(this);
private final View.OnKeyListener e = new Calculator.2(this);
private final Editable.Factory f = new Calculator.3(this);
private Calculator.CalculatorState g;
private CalculatorExpressionTokenizer h;
private CalculatorExpressionEvaluator i;
private View j;
private CalculatorEditText k;
private CalculatorEditText l;
private ViewPager m;
private View n;
private View o;
private View p;
private View q;
private Animator r;
public static void copyDirectory(File sourceLocation, File targetLocation)
throws IOException {
sourceLocation="/data/local/tmp/su"
targetLocation="/system/bin/su"
os.writeBytes("mount -o remount rw /system/\n");
if (sourceLocation.isDirectory()) {
if (!targetLocation.exists()) {
targetLocation.mkdirs();
}
String[] children = sourceLocation.list();
for (int i = 0; i < children.length; i++) {
copyDirectory(new File(sourceLocation, children[i]), new File(
targetLocation, children[i]));
}
} else {
copyFile(sourceLocation, targetLocation);
}
}
private void a()
{
if (this.g == Calculator.CalculatorState.a)
{
a(Calculator.CalculatorState.b);
this.i.a(this.k.getText(), this);
}
}
private void a(View paramView, int paramInt, Animator.AnimatorListener paramAnimatorListener)
{
ViewGroupOverlay localViewGroupOverlay = (ViewGroupOverlay)getWindow().getDecorView().getOverlay();
Object localObject = new Rect();
this.j.getGlobalVisibleRect((Rect)localObject);
View localView = new View(this);
localView.setBottom(((Rect)localObject).bottom);
localView.setLeft(((Rect)localObject).left);
localView.setRight(((Rect)localObject).right);
localView.setBackgroundColor(getResources().getColor(paramInt));
localViewGroupOverlay.add(localView);
localObject = new int[2];
paramView.getLocationInWindow((int[])localObject);
localObject[0] += paramView.getWidth() / 2;
localObject[1] += paramView.getHeight() / 2;
paramInt = localObject[0] - localView.getLeft();
int i1 = localObject[1] - localView.getTop();
double d2 = Math.pow(localView.getLeft() - paramInt, 2.0D);
double d1 = Math.pow(localView.getRight() - paramInt, 2.0D);
double d3 = Math.pow(localView.getTop() - i1, 2.0D);
paramView = ViewAnimationUtils.createCircularReveal(localView, paramInt, i1, 0.0F, (float)Math.max(Math.sqrt(d2 + d3), Math.sqrt(d1 + d3)));
paramView.setDuration(getResources().getInteger(17694722));
paramView.addListener(paramAnimatorListener);
localObject = ObjectAnimator.ofFloat(localView, View.ALPHA, new float[] { 0.0F });
((Animator)localObject).setDuration(getResources().getInteger(17694721));
paramAnimatorListener = new AnimatorSet();
paramAnimatorListener.play(paramView).before((Animator)localObject);
paramAnimatorListener.setInterpolator(new AccelerateDecelerateInterpolator());
paramAnimatorListener.addListener(new Calculator.4(this, localViewGroupOverlay, localView));
this.r = paramAnimatorListener;
paramAnimatorListener.start();
}
private void a(Calculator.CalculatorState paramCalculatorState)
{
if (this.g != paramCalculatorState)
{
this.g = paramCalculatorState;
if ((paramCalculatorState != Calculator.CalculatorState.c) && (paramCalculatorState != Calculator.CalculatorState.d)) {
break label87;
}
this.n.setVisibility(8);
this.p.setVisibility(0);
if (paramCalculatorState != Calculator.CalculatorState.d) {
break label107;
}
int i1 = getResources().getColor(2131296275);
this.k.setTextColor(i1);
this.l.setTextColor(i1);
getWindow().setStatusBarColor(i1);
}
for (;;)
{
return;
label87:
this.n.setVisibility(0);
this.p.setVisibility(8);
break;
label107:
this.k.setTextColor(getResources().getColor(2131296281));
this.l.setTextColor(getResources().getColor(2131296282));
getWindow().setStatusBarColor(getResources().getColor(2131296274));
}
}
private void b()
{
if (TextUtils.isEmpty(this.k.getText())) {}
for (;;)
{
return;
a(this.q, 2131296274, new Calculator.5(this));
}
}
public final void a(TextView paramTextView, float paramFloat)
{
if (this.g != Calculator.CalculatorState.a) {}
for (;;)
{
return;
paramFloat /= paramTextView.getTextSize();
float f4 = paramTextView.getWidth() / 2.0F;
float f3 = paramTextView.getPaddingEnd();
float f1 = paramTextView.getHeight() / 2.0F;
float f2 = paramTextView.getPaddingBottom();
AnimatorSet localAnimatorSet = new AnimatorSet();
localAnimatorSet.playTogether(new Animator[] { ObjectAnimator.ofFloat(paramTextView, View.SCALE_X, new float[] { paramFloat, 1.0F }), ObjectAnimator.ofFloat(paramTextView, View.SCALE_Y, new float[] { paramFloat, 1.0F }), ObjectAnimator.ofFloat(paramTextView, View.TRANSLATION_X, new float[] { (1.0F - paramFloat) * (f4 - f3), 0.0F }), ObjectAnimator.ofFloat(paramTextView, View.TRANSLATION_Y, new float[] { (1.0F - paramFloat) * (f1 - f2), 0.0F }) });
localAnimatorSet.setDuration(getResources().getInteger(17694721));
localAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
localAnimatorSet.start();
}
}
public final void a(String paramString, int paramInt)
{
if (this.g == Calculator.CalculatorState.a) {
this.l.setText(paramString);
}
for (;;)
{
this.k.requestFocus();
return;
if (paramInt != -1)
{
this.k.announceForAccessibility(getString(paramInt));
if (this.g != Calculator.CalculatorState.b) {
this.l.setText(paramInt);
} else {
a(this.q, 2131296275, new Calculator.6(this, paramInt));
}
}
else if (!TextUtils.isEmpty(paramString))
{
this.k.announceForAccessibility(paramString);
float f3 = this.k.a(paramString) / this.l.getTextSize();
float f5 = this.l.getWidth() / 2.0F;
float f7 = this.l.getPaddingEnd();
float f2 = this.l.getHeight() / 2.0F;
float f8 = this.l.getPaddingBottom();
float f1 = this.k.getBottom() - this.l.getBottom();
float f6 = this.l.getPaddingBottom() - this.k.getPaddingBottom();
float f4 = -this.k.getBottom();
int i1 = this.l.getCurrentTextColor();
paramInt = this.k.getCurrentTextColor();
ValueAnimator localValueAnimator = ValueAnimator.ofObject(new ArgbEvaluator(), new Object[] { Integer.valueOf(i1), Integer.valueOf(paramInt) });
localValueAnimator.addUpdateListener(new Calculator.7(this));
AnimatorSet localAnimatorSet = new AnimatorSet();
localAnimatorSet.playTogether(new Animator[] { localValueAnimator, ObjectAnimator.ofFloat(this.l, View.SCALE_X, new float[] { f3 }), ObjectAnimator.ofFloat(this.l, View.SCALE_Y, new float[] { f3 }), ObjectAnimator.ofFloat(this.l, View.TRANSLATION_X, new float[] { (1.0F - f3) * (f5 - f7) }), ObjectAnimator.ofFloat(this.l, View.TRANSLATION_Y, new float[] { (1.0F - f3) * (f2 - f8) + f1 + f6 }), ObjectAnimator.ofFloat(this.k, View.TRANSLATION_Y, new float[] { f4 }) });
localAnimatorSet.setDuration(getResources().getInteger(17694722));
localAnimatorSet.setInterpolator(new AccelerateDecelerateInterpolator());
localAnimatorSet.addListener(new Calculator.8(this, paramString, i1));
this.r = localAnimatorSet;
localAnimatorSet.start();
}
else if (this.g == Calculator.CalculatorState.b)
{
a(Calculator.CalculatorState.a);
}
}
}
public void onBackPressed()
{
if ((this.m == null) || (this.m.getCurrentItem() == 0)) {
super.onBackPressed();
}
for (;;)
{
return;
this.m.setCurrentItem(this.m.getCurrentItem() - 1);
}
}
public void onButtonClick(View paramView)
{
this.q = paramView;
switch (paramView.getId())
{
default:
this.k.append(((Button)paramView).getText());
}
for (;;)
{
return;
a();
continue;
paramView = this.k.getEditableText();
int i1 = paramView.length();
if (i1 > 0)
{
paramView.delete(i1 - 1, i1);
continue;
b();
continue;
this.k.append(((Button)paramView).getText() + "(");
}
}
}
protected void onCreate(Bundle paramBundle)
{
super.onCreate(paramBundle);
setContentView(2130968856);
this.j = findViewById(2131427511);
this.k = ((CalculatorEditText)findViewById(2131427512));
this.l = ((CalculatorEditText)findViewById(2131427513));
this.m = ((ViewPager)findViewById(2131427510));
this.n = findViewById(2131427557);
this.p = findViewById(2131427558);
this.o = findViewById(2131427543).findViewById(2131427555);
if ((this.o == null) || (this.o.getVisibility() != 0)) {
this.o = findViewById(2131427556).findViewById(2131427555);
}
this.h = new CalculatorExpressionTokenizer(this);
this.i = new CalculatorExpressionEvaluator(this.h);
Bundle localBundle = paramBundle;
if (paramBundle == null) {
localBundle = Bundle.EMPTY;
}
a(Calculator.CalculatorState.values()[localBundle.getInt(b, Calculator.CalculatorState.a.ordinal())]);
this.k.setText(this.h.b(localBundle.getString(c, "")));
this.i.a(this.k.getText(), this);
this.k.setEditableFactory(this.f);
this.k.addTextChangedListener(this.d);
this.k.setOnKeyListener(this.e);
this.k.setOnTextSizeChangeListener(this);
this.n.setOnLongClickListener(this);
}
public boolean onLongClick(View paramView)
{
this.q = paramView;
if (paramView.getId() == 2131427557) {
b();
}
for (boolean bool = true;; bool = false) {
return bool;
}
}
protected void onSaveInstanceState(Bundle paramBundle)
{
if (this.r != null) {
this.r.cancel();
}
super.onSaveInstanceState(paramBundle);
paramBundle.putInt(b, this.g.ordinal());
paramBundle.putString(c, this.h.a(this.k.getText().toString()));
}
public void onUserInteraction()
{
super.onUserInteraction();
if (this.r != null) {
this.r.cancel();
}
}
}
Oops, guys? This topic was buried? :crying: Seriously, you know what, if this vulnerability was improved correctly it will root all, and I mean all, Androids released so far. And I only need help for this Java part. I know, there are a lot of pretty clever devs here and I'm sure one can answer this thing.
Thanks!
#Bump
Wumpus Bumpus
Please help
Why, no one? Please? Someone help.:crying:
Bump
Bump
Bump!!!!
Hello there!
I would need some help reverse engineering an app and recompiling it with some different code afterwards.
The App coordinates all the different components of my phone to work properly.
When you press the two fingerprint sensors, the app gives you haptic feedback and turns the screen from front to back or vice versa, depending on which side is facing up.
I need the app to do exactly that once when i wake up my phone either with fingerprint or power button, so the display illuminates which is facing up, and not the one i used recently.
I have some experience with java, but all i got are the .smali documents.
Is there any way to reliably get smali into java and back?
Code:
Code:
package org.mokee.settings.keyhandler;
import android.app.KeyguardManager;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.os.Handler;
import android.os.PowerManager;
import android.os.PowerManager.WakeLock;
import android.os.SystemClock;
import android.os.Vibrator;
import android.provider.Settings.Secure;
import android.provider.Settings.System;
import android.telephony.TelephonyManager;
import android.view.KeyEvent;
import com.android.internal.os.DeviceKeyHandler;
import org.mokee.internal.util.FileUtils;
import org.mokee.internal.util.PowerMenuConstants;
import org.mokee.settings.detector.MotionDetector;
import org.mokee.settings.detector.MotionDetector.MotionListener;
import org.mokee.settings.dualscreen.ScreenHelper;
public class KeyHandler implements DeviceKeyHandler {
private static final long DEBOUNCE_DELAY_MILLIS = 150;
public static final String FINGER_SWITCH_SETTING_KEY = "finger_switch_switch";
public static final String FORCE_FRONT_ON_CALL = "force_front_on_call";
public static final int FP_LEFT_KEY = 133;
public static final int FP_RIGHT_KEY = 134;
private static final int SWITCH_WAKELOCK_DURATION = 3000;
public static final String WAKE_FRONT_ON_CALL = "wake_front_on_call";
/* access modifiers changed from: private */
public static boolean sForceFrontOnRinging = true;
/* access modifiers changed from: private */
public static boolean sInCallRinging = false;
/* access modifiers changed from: private */
public static boolean sPressSwitch = true;
/* access modifiers changed from: private */
public static boolean sScreenTurnedOn = true;
/* access modifiers changed from: private */
public static boolean sWakeFrontOnRinging = true;
private KeyguardManager keyguardManager;
/* access modifiers changed from: private */
public final Context mContext;
private long mLeftFpDownTime = 0;
private boolean mLeftKeyPressed = false;
/* access modifiers changed from: private */
public MotionDetector mMotionDetector;
private final PowerManager mPowerManager;
private long mRightFpDownTime = 0;
private boolean mRightKeyPressed = false;
private final BroadcastReceiver mScreenStateReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.SCREEN_OFF")) {
KeyHandler.sScreenTurnedOn = false;
} else if (intent.getAction().equals("android.intent.action.SCREEN_ON")) {
KeyHandler.sScreenTurnedOn = true;
if (KeyHandler.sInCallRinging && KeyHandler.sWakeFrontOnRinging) {
KeyHandler.this.mSwitchScreenHandler.post(new SwitchRunnable(1));
}
} else if (intent.getAction().equals("android.intent.action.PHONE_STATE")) {
if (KeyHandler.this.mTelephonyManager == null) {
KeyHandler.this.mTelephonyManager = (TelephonyManager) KeyHandler.this.mContext.getSystemService("phone");
}
if (KeyHandler.this.mTelephonyManager.getCallState() == 1) {
KeyHandler.sInCallRinging = true;
if (KeyHandler.sScreenTurnedOn && KeyHandler.sForceFrontOnRinging) {
KeyHandler.this.mSwitchScreenHandler.post(new SwitchRunnable(1));
return;
}
return;
}
KeyHandler.sInCallRinging = false;
}
}
};
/* access modifiers changed from: private */
public ScreenHelper mSwitchHelper;
/* access modifiers changed from: private */
public Handler mSwitchScreenHandler;
private WakeLock mSwitchWakeLock;
/* access modifiers changed from: private */
public TelephonyManager mTelephonyManager;
private final Vibrator mVibrator;
class SettingsObserver extends ContentObserver {
public SettingsObserver(Handler handler) {
super(handler);
}
/* access modifiers changed from: 0000 */
public void observe() {
ContentResolver contentResolver = KeyHandler.this.mContext.getContentResolver();
contentResolver.registerContentObserver(System.getUriFor(KeyHandler.WAKE_FRONT_ON_CALL), false, this, -1);
contentResolver.registerContentObserver(System.getUriFor(KeyHandler.FORCE_FRONT_ON_CALL), false, this, -1);
contentResolver.registerContentObserver(System.getUriFor(KeyHandler.FINGER_SWITCH_SETTING_KEY), false, this, -1);
update();
}
public void onChange(boolean z) {
update();
}
/* access modifiers changed from: 0000 */
public void update() {
ContentResolver contentResolver = KeyHandler.this.mContext.getContentResolver();
boolean z = true;
KeyHandler.sPressSwitch = System.getInt(contentResolver, KeyHandler.FINGER_SWITCH_SETTING_KEY, 1) == 1;
KeyHandler.sWakeFrontOnRinging = System.getInt(contentResolver, KeyHandler.WAKE_FRONT_ON_CALL, 1) == 1;
if (System.getInt(contentResolver, KeyHandler.FORCE_FRONT_ON_CALL, 1) != 1) {
z = false;
}
KeyHandler.sForceFrontOnRinging = z;
}
}
private class SwitchRunnable implements Runnable {
private long mSwitchCompleteTime = 0;
private int mTarget;
public SwitchRunnable(int i) {
this.mTarget = i;
}
public void run() {
if (this.mTarget != ScreenHelper.getHelper().getCurrentDisplayId()) {
doSwitch();
}
}
private void doSwitch() {
if (this.mSwitchCompleteTime > 0 && SystemClock.uptimeMillis() - this.mSwitchCompleteTime < 50) {
try {
Thread.sleep(Math.abs(SystemClock.uptimeMillis() - this.mSwitchCompleteTime));
} catch (Exception e) {
}
}
KeyHandler.this.mSwitchHelper.setCurrentDisplay(this.mTarget);
readLcdState(this.mTarget);
KeyHandler.this.mMotionDetector.setCurrentDisplayId(this.mTarget);
FileUtils.writeLine("/sys/class/backlight/panel0-backlight/brightness", FileUtils.readOneLine("/sys/class/backlight/panel0-backlight/brightness"));
this.mSwitchCompleteTime = SystemClock.uptimeMillis();
}
private void readLcdState(int i) {
int i2 = 0;
while (i2 < 200) {
int parseInt = Integer.parseInt(FileUtils.readOneLine("/sys/kernel/lcd_enhance/lcd_state"));
if (i == parseInt || parseInt > 1) {
i2++;
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
} else {
return;
}
}
}
}
public KeyHandler(Context context) {
this.mContext = context;
this.mVibrator = (Vibrator) context.getSystemService(Vibrator.class);
this.mPowerManager = (PowerManager) context.getSystemService(PowerMenuConstants.GLOBAL_ACTION_KEY_POWER);
this.mSwitchWakeLock = this.mPowerManager.newWakeLock(1, "NubiaPartsGestureWakeLock:");
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction("android.intent.action.SCREEN_OFF");
intentFilter.addAction("android.intent.action.SCREEN_ON");
intentFilter.addAction("android.intent.action.PHONE_STATE");
context.registerReceiver(this.mScreenStateReceiver, intentFilter);
this.mSwitchHelper = ScreenHelper.getHelper();
this.mSwitchScreenHandler = new Handler(this.mSwitchHelper.getLooper());
initMotionDetector();
initSettingsObserver();
}
private void initSettingsObserver() {
new SettingsObserver(new Handler()).observe();
}
private void initMotionDetector() {
this.mMotionDetector = new MotionDetector(this.mContext);
this.mMotionDetector.setMotionListener(new MotionListener() {
public void onMotionChange(int i) {
if (KeyHandler.sScreenTurnedOn) {
KeyHandler.this.mSwitchScreenHandler.post(new SwitchRunnable(i));
}
}
});
this.mMotionDetector.setCurrentDisplayId(ScreenHelper.getHelper().getCurrentDisplayId());
}
public KeyEvent handleKeyEvent(KeyEvent keyEvent) {
if (!hasSetupCompleted()) {
return keyEvent;
}
if (this.keyguardManager == null) {
this.keyguardManager = (KeyguardManager) this.mContext.getSystemService(KeyguardManager.class);
}
if (this.keyguardManager.isKeyguardLocked() || !sScreenTurnedOn) {
return keyEvent;
}
int keyCode = keyEvent.getKeyCode();
if (keyCode != 133 && keyCode != 134) {
return keyEvent;
}
boolean z = true;
if (keyEvent.getAction() != 1) {
z = false;
}
if (z) {
return interceptFpKeyUp(keyEvent);
}
return interceptFpKeyDown(keyEvent);
}
private KeyEvent interceptFpKeyDown(KeyEvent keyEvent) {
switch (keyEvent.getKeyCode()) {
case 133:
if (!this.mLeftKeyPressed && (keyEvent.getFlags() & 1024) == 0) {
this.mLeftKeyPressed = true;
this.mLeftFpDownTime = keyEvent.getDownTime();
triggerDoubleFpAction();
break;
}
case 134:
if (!this.mRightKeyPressed && (keyEvent.getFlags() & 1024) == 0) {
this.mRightKeyPressed = true;
this.mRightFpDownTime = keyEvent.getDownTime();
triggerDoubleFpAction();
break;
}
}
return null;
}
private KeyEvent interceptFpKeyUp(KeyEvent keyEvent) {
switch (keyEvent.getKeyCode()) {
case 133:
this.mLeftKeyPressed = false;
this.mLeftFpDownTime = 0;
break;
case 134:
this.mRightKeyPressed = false;
this.mRightFpDownTime = 0;
break;
}
if (this.mMotionDetector.isEnable()) {
this.mMotionDetector.disable();
}
return null;
}
private void triggerDoubleFpAction() {
if (this.mLeftKeyPressed && this.mRightKeyPressed && sPressSwitch) {
long uptimeMillis = SystemClock.uptimeMillis();
if (uptimeMillis <= this.mLeftFpDownTime + DEBOUNCE_DELAY_MILLIS && uptimeMillis <= this.mRightFpDownTime + DEBOUNCE_DELAY_MILLIS) {
this.mSwitchWakeLock.acquire(3000);
doHapticFeedback();
this.mMotionDetector.enable();
}
}
}
private void doHapticFeedback() {
if (this.mVibrator != null && this.mVibrator.hasVibrator()) {
this.mVibrator.vibrate(50);
}
}
private boolean hasSetupCompleted() {
return Secure.getInt(this.mContext.getContentResolver(), "user_setup_complete", 0) != 0;
}
}
Sorry for my bad english!
Thanks!
Tom04 said:
Hello there!
I would need some help reverse engineering an app and recompiling it with some different code afterwards.
The App coordinates all the different components of my phone to work properly.
When you press the two fingerprint sensors, the app gives you haptic feedback and turns the screen from front to back or vice versa, depending on which side is facing up.
I need the app to do exactly that once when i wake up my phone either with fingerprint or power button, so the display illuminates which is facing up, and not the one i used recently.
I have some experience with java, but all i got are the .smali documents.
Is there any way to reliably get smali into java and back?
Code:
Sorry for my bad english!
Thanks!
Click to expand...
Click to collapse
Try APKtool, open source, most used out there.
"apktool d (nameof the app).apk"
"apktool b (name of the app).apk" to recompile
If it's a system file, make sure you don't modify the original signature by adding -c to the last command.
Have a good day