Calling Hidden API in Android to Turn Screen Off

Calling hidden API in android to turn screen off

Here's what I did to work around the need to make the screen sleep. You can do this in an activity window. I paired it with reducing the sleep timeout to 5 sec for this custom lockscreen activity. You can view all my source over at my project page, but here's the relevant part about turning the screen off that worked for me on a droid.

public void setBright(float value) {
Window mywindow = getWindow();
WindowManager.LayoutParams lp = mywindow.getAttributes();
lp.screenBrightness = value;
mywindow.setAttributes(lp);
}

//call this task to turn off the screen in a fadeout.

class Task implements Runnable {
public void run() {
if (bright != 0) {
setBright(bright/100); //start at 10% bright and go to 0 (screen off)
bright--;
serviceHandler.postDelayed(myTask, 100L);
} else {
setBright((float) 0.0);
bright = 10;//put bright back
}
}
}

I used the handler task as a test for the method, it worked when I called it from onBackPressed in the first build. Now, I just have the activity setBright to 0.0 at onCreate. This makes it so the screen doesn't actually turn on even if my user wakes the CPU by an accidental volume key press. When I want the screen to go on, I have the key event call setBright to a value greater than 0 (1.0 means max bright). I'm very lucky this works for my custom lockscreen activity. I found that changing the literal brightness system setting doesn't work like this, and won't get the screen off.

check out my other source over on my project svn http://code.google.com/p/mylockforandroid/source/checkout

How hard do you think it is to ask the android team to add support for turning the screen off or defining whether the screen should wake via Lock mediator replacement similarly to how you could program an alternative Home Launcher app?

Turn off screen programmatically when face is close the screen on Android

I found solution by disassembling one very famous VoIP application. This activity after pressing button1 will disable screen and hardware keys when you close sensors. After pressing button2 this function will be switched off.

Also, this function required permission:

<uses-permission android:name="android.permission.WAKE_LOCK" />

Activity. Try it.

public class MainActivity extends Activity {

private Button button1;
private Button button2;
private PowerManager powerManager;
private PowerManager.WakeLock wakeLock;
private int field = 0x00000020;

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

try {
// Yeah, this is hidden field.
field = PowerManager.class.getClass().getField("PROXIMITY_SCREEN_OFF_WAKE_LOCK").getInt(null);
} catch (Throwable ignored) {
}

powerManager = (PowerManager) getSystemService(POWER_SERVICE);
wakeLock = powerManager.newWakeLock(field, getLocalClassName());

setContentView(R.layout.main);
button1 = (Button) findViewById(R.id.button1);
button2 = (Button) findViewById(R.id.button2);

button1.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(!wakeLock.isHeld()) {
wakeLock.acquire();
}
}
});

button2.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
if(wakeLock.isHeld()) {
wakeLock.release();
}
}
});
}
}

Android: Turn off screen from a service

I see two options:

(1) Create a dummy Activity and use it to get a Window object through the getWindow(); method. Then you would use an Intent to call the screen off from your Service.

(2) Use IHardwareService.Stub. Not part of the SDK, but there's a workaround in this blog post: http://www.tutorialforandroid.com/2009/01/changing-screen-brightness.html

BTW: I would strongly recommend the first option. You never know when a class that is not part of the SDK might change.

How to turn screen off based on proximity sensor?

An example project can be found here on GitHub

First you need to declare that you are using Wakelock in AndroidManifest.xml :

<uses-permission android:name="android.permission.WAKE_LOCK" />

Then in your activity import PowerManager

import android.os.PowerManager

Declare your attributes

private lateinit var powerManager: PowerManager
private lateinit var lock: PowerManager.WakeLock

In onCreate method instantiate them :
(replace "simplewakelock:wakelocktag" with another unique tag)

powerManager = getSystemService(Context.POWER_SERVICE) as PowerManager
lock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,"simplewakelock:wakelocktag")

Then you can enable and disable the lock (and the behaviour) using :

// Enable : Acquire the lock if it was not already acquired
if(!lock.isHeld) lock.acquire()

// Disable : Release the lock if it was not already released
if(lock.isHeld) lock.release()

Just put it where you want and don’t forget to release the lock when you don’t need it anymore (onPause can be a good place), otherwise it will continue even if you switch app.

display a button that can turn off the screen like the power button

Hi try looking at a previous thread.

Calling hidden API in android to turn screen off

But if you are just learning Android, there might be more simple things to try first :) see the developer guide on http://developer.android.com/guide/index.html

Bypass Android's hidden API restrictions

There are actually a few ways to do this.



Secure Settings

Google built in a way to disable the hidden API restrictions globally on a given Android device, for testing purposes. The section in the link in the question titled How can I enable access to non-SDK interfaces? says the following:

You can enable access to non-SDK interfaces on development devices by changing the API enforcement policy using the following adb commands:

adb shell settings put global hidden_api_policy_pre_p_apps  1
adb shell settings put global hidden_api_policy_p_apps 1

To reset the API enforcement policy to the default settings, use the following commands:

adb shell settings delete global hidden_api_policy_pre_p_apps
adb shell settings delete global hidden_api_policy_p_apps

These commands do not require a rooted device.

You can set the integer in the API enforcement policy to one of the following values:

  • 0: Disable all detection of non-SDK interfaces. Using this setting disables all log messages for non-SDK interface usage and prevents you from testing your app using the StrictMode API. This setting is not recommended.
  • 1: Enable access to all non-SDK interfaces, but print log messages with warnings for any non-SDK interface usage. Using this setting also allows you to test your app using the StrictMode API.
  • 2: Disallow usage of non-SDK interfaces that belong to either the blacklist or the greylist and are restricted for your target API level.
  • 3: Disallow usage of non-SDK interfaces that belong to the blacklist, but allow usage of interfaces that belong to the greylist and are restricted for your target API level.

(On the Q betas, there seems to be only one key now: hidden_api_policy.)

(In my testing, after changing this setting, your app needs to be fully restarted—process killed–for it to take effect.)

You can even change this from inside an app with Settings.Global.putInt(ContentResolver, String, Int). However, it requires the app to hold the WRITE_SECURE_SETTINGS permission, which is only automatically granted to signature-level or privileged apps. It can be manually granted through ADB.



JNI

All APIs Including API 30 and Later

The previous method is only functional for apps targeting API 29 and below. For apps targeting API 30 and above, use this library: https://github.com/ChickenHook/RestrictionBypass.

I don't fully understand how this works, but it seems to abuse the creation of Java Threads inside the JNI to set the current app's hidden API exemption policy to allow access to all hidden APIs.

Here's a full description of how it works: https://androidreverse.wordpress.com/2020/05/02/android-api-restriction-bypass-for-all-android-versions/.

The usage is simple. Make sure you have JitPack added to your repositories (in the project-level build.gradle):

allprojects {
repositories {
[..]
maven { url "https://jitpack.io" }
}
}

Then implement the library:

implementation 'com.github.ChickenHook:RestrictionBypass:2.2'

It will automatically remove the API restrictions for you.

API 29 and Earlier

The secure settings method is good for testing or for personal apps, but if your app is meant to be distributed to devices you don't control, trying to instruct end users on how to use ADB can be a nightmare, and even if they already know what to do, it's inconvenient.

Luckily, there is actually a way to disable the API restrictions for your app, using some clever tricks in native code.

Inside your JNI_OnLoad() method, you can do the following:

static art::Runtime* runtime = nullptr;

extern "C" jint JNI_OnLoad(JavaVM *vm, void *reserved) {
...

runtime = reinterpret_cast<art::JavaVMExt*>(vm)->GetRuntime();
runtime->SetHiddenApiEnforcementPolicy(art::hiddenapi::EnforcementPolicy::kNoChecks);

...
}

This will disable the hidden API checks for you, without any special permissions.

Source

There's also a library you can use that will do this for you: https://github.com/tiann/FreeReflection/



Pure Java/Kotlin

JNI isn't for everyone (including me). It also needs you to have separate versions of your app for different architectures. Luckily, there are also pure-Java solutions.

All APIs Including API 30 and Later

The team behind LSPosed, a replacement for the popular Xposed framework, has come up with a pure-Java solution for bypassing hidden API restrictions for apps targeting API 28 or later.

The library is over at their GitHub: https://github.com/LSPosed/AndroidHiddenApiBypass.

The explanation is in Chinese, but the gist of it seems to be this. The library uses Java's Unsafe API as an alternative to reflection. It then works very similarly to the method for API 29 and earlier, allowing the user to set the hidden API exemptions.

To use it, just implement the library:

implementation 'org.lsposed.hiddenapibypass:hiddenapibypass:2.0'

And then set the hidden API exemptions when your application starts:

if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
HiddenApiBypass.addHiddenApiExemptions("L");
}

API 29 and Earlier

Android's hidden API restrictions only apply to third party apps that aren't signed by the platform signature and aren't manually whitelisted in /system/etc/sysconfig/. What this means is that the framework (obviously) can access any hidden methods it wants, which is what this method takes advantage of.

The solution here is to use double-reflection (or "meta-reflection," as the translated source calls it). Here's an example, retrieving a hidden method (in Kotlin):

val getDeclaredMethod = Class::class.java.getDeclaredMethod("getDeclaredMethod", String::class.java, arrayOf<Class<*>>()::class.java)

val someHiddenMethod = getDeclaredMethod.invoke(SomeClass::class.java, "someHiddenMethod", Param1::class.java, Param2::class.java)

val result = someHiddenMethod.invoke(someClassInstance, param1, param2)

Now, this could stand as a good enough solution on its own, but it can be taken a step further. The class dalvik.system.VMRuntime has a method: setHiddenApiExemptions(vararg methods: String). Simply passing "L" to this method will exempt all hidden APIs, and we can do that with double-reflection.

val forName = Class::class.java.getDeclaredMethod("forName", String::class.java)
val getDeclaredMethod = Class::class.java.getDeclaredMethod("getDeclaredMethod", String::class.java, arrayOf<Class<*>>()::class.java)

val vmRuntimeClass = forName.invoke(null, "dalvik.system.VMRuntime") as Class<*>
val getRuntime = getDeclaredMethod.invoke(vmRuntimeClass, "getRuntime", null) as Method
val setHiddenApiExemptions = getDeclaredMethod.invoke(vmRuntimeClass, "setHiddenApiExemptions", arrayOf(arrayOf<String>()::class.java)) as Method

val vmRuntime = getRuntime.invoke(null)

setHiddenApiExemptions.invoke(vmRuntime, arrayOf("L"))

Put that code in your Application class' onCreate() method, for example, and then you'll be able to use hidden APIs like normal.

For a full Java example of this, check out the FreeReflection library linked in the JNI section, or follow through the source below.

Source

Lock or turn off the screen programmatically

Well something with high necessity can't finished with two lines of code, lock off screen required device admin. you may follow this :

private void lock() {
PowerManager pm = (PowerManager)getSystemService(Context.POWER_SERVICE);
if (pm.isScreenOn()) {
DevicePolicyManager policy = (DevicePolicyManager)
getSystemService(Context.DEVICE_POLICY_SERVICE);
try {
policy.lockNow();
} catch (SecurityException ex) {
Toast.makeText(
this,
"must enable device administrator",
Toast.LENGTH_LONG).show();
ComponentName admin = new ComponentName(context, AdminReceiver.class);
Intent intent = new Intent(
DevicePolicyManager.ACTION_ADD_DEVICE_ADMIN).putExtra(
DevicePolicyManager.EXTRA_DEVICE_ADMIN, admin);
context.startActivity(intent);
}
}
}

and AdminReceiverClass:

public class AdminReceiver extends DeviceAdminReceiver {
public static final String ACTION_DISABLED = "device_admin_action_disabled";
public static final String ACTION_ENABLED = "device_admin_action_enabled";

@Override
public void onDisabled(Context context, Intent intent) {
super.onDisabled(context, intent);
LocalBroadcastManager.getInstance(context).sendBroadcast(
new Intent(ACTION_DISABLED));
}
@Override
public void onEnabled(Context context, Intent intent) {
super.onEnabled(context, intent);
LocalBroadcastManager.getInstance(context).sendBroadcast(
new Intent(ACTION_ENABLED));
}
}

also we need declares the security policies used in metadata so for examples with Path android:resource="@xml/device_admin_sample" :

 <device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<limit-password />
<watch-login />
<reset-password />
<force-lock />
<wipe-data />
<expire-password />
<encrypted-storage />
<disable-camera />
</uses-policies>
</device-admin>

in our case we just need :

<?xml version="1.0" encoding="utf-8"?>
<device-admin xmlns:android="http://schemas.android.com/apk/res/android">
<uses-policies>
<force-lock />
</uses-policies>
</device-admin>`

Now declare it in our manifist.xml :

<receiver
android:name=".AdminReceiver"
android:label="@string/device_admin"
android:description="@string/device_admin_description"
android:permission="android.permission.BIND_DEVICE_ADMIN">
<meta-data
android:name="android.app.device_admin"
android:resource="@xml/device_admin_sample" />
<intent-filter>
<action android:name="android.app.action.DEVICE_ADMIN_ENABLED" />
</intent-filter>
</receiver>`

Hope it will Help you.



Related Topics



Leave a reply



Submit