I am building an app that requires a lot of drawing on the canvas. I notice that the app is a bit laggy in devices with high resolution (nexus 7 for example). I saw there is a Force GPU option in the developer option. When Force GPU is enabled, my app runs absolutely smooth.
I have read that this Force GPU option is called Hardware Acceleration and it is available only for Android 3.0 and above.
My app is targeting Android 2.3 and above.
Is it possible to programmatically enable Hardware Accelerated (or Force GPU--whatever the magic is called) on any Android 3.0 or above devices?
Something like:
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB){
Turn On Hardware Accelerate HERE but How can i do this?
any code snippet would be welcome/helpful/thanks
}
I assume you've already added android:hardwareAccelerated to your Manifest file?
<application android:hardwareAccelerated="true" ...>
That is what enables hardware acceleration within your application per the guide on hardware acceleration and should do exactly what forcing GPU does at a system level.
Set minSdkVersion to 10 and targetSdkVersion to maximum
Like below
<uses-sdk
android:minSdkVersion="10"
android:targetSdkVersion="17" />
then
<application android:hardwareAccelerated="true" ...>
Now will work
And for particularities
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB){
view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
}
or
if(android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB){
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
If you want to build your application using lower api level you can access the method via reflection:
try {
Method setLayerType = view.getClass().getMethod(
"setLayerType", new Class[] { int.class, Paint.class });
if (setLayerType != null)
setLayerType.invoke(view, new Object[] { LAYER_TYPE_X, null });
} catch (NoSuchMethodException e) {
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
Where LAYER_TYPE_X is the constant integer value of wanted layer type:
LAYER_TYPE_NONE = 0
LAYER_TYPE_SOFTWARE = 1
LAYER_TYPE_HARDWARE = 2
Related
public boolean WifiManager.setWifiEnabled (boolean enabled)
This method was deprecated in API level 29. Starting with
Build.VERSION_CODES#Q, applications are not allowed to enable/disable
Wi-Fi. Compatibility Note: For applications targeting
Build.VERSION_CODES.Q or above, this API will always return false and
will have no effect. If apps are targeting an older SDK (
Build.VERSION_CODES.P or below), they can continue to use this API.
How can we disable WiFi on Android 29?
In Android Q (Android 10, API level 29) you can't enable/disable wifi programmatically anymore. Use Settings Panel to toggle wifi connectivity:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
val panelIntent = Intent(Settings.Panel.ACTION_INTERNET_CONNECTIVITY)
startActivityForResult(panelIntent, 0)
} else {
// add appropriate permissions to AndroidManifest file (see https://stackoverflow.com/questions/3930990/android-how-to-enable-disable-wifi-or-internet-connection-programmatically/61289575)
(this.context?.getSystemService(Context.WIFI_SERVICE) as? WifiManager)?.apply { isWifiEnabled = true /*or false*/ }
}
This is a much simpler way of detecting the operating system version:
if (Build.VERSION.SDK_INT<Build.VERSION_CODES.Q)
wifiManager.setWifiEnabled(status);
else
{
Intent panelIntent = new Intent(Settings.Panel.ACTION_WIFI);
startActivityForResult(panelIntent,1);
}
Basically, if the OS version is less than Android Q, use the WifiManager class object to enable/disable the use of Wi-Fi; otherwise, use implicit Intents to disable Wi-Fi.
Android Q has restricted this and developers can't disable wifi programmatically. your app will continue to work and can disable wifi if your targetSdkVersion <= 28
solved!
private void setWifiEnabled(boolean enabled) {
try {
Runtime.getRuntime().exec(new String[] { "su", "-c", "svc wifi", enabled ?
"enable" :
"disable" });
}
catch (IOException e) {
e.printStackTrace();
}
}
happily works on api 29
obviously, this requires root
does NOT require android.permission.CHANGE_WIFI_STATE
Toggling WiFi will not be allowed by apps starting from Android Q according to Google.
Here's the issue on their issuetracker: https://issuetracker.google.com/issues/128554616
I want to launch NFC settings activity, which is done using action ACTION_WIRELESS_SETTINGS prior to API level 16. But in API level 16 and above it is done using ACTION_NFC_SETTINGS.
I am compiling my source using Android 4.0.3 which is API level 15.
How can I support for higher level so that it can open NFC settings in all versions.
Do i need to compile my source with API level 16 or higher and make min sdk version 15?
You would typically compile your application with the SDK of the highest API version that you use in your code (or the latest available SDK). In your app's manifest you add the minimum and target SDK versions:
<uses-sdk android:minSdkVersion="..." android:targetSdkVersion="..." />
These values define how your app will be treated on a device in terms of (backwards) compatibility features.
Then, in your code, whenever you use API calles that are not available on a certain API level, you would surround those calles with a check for the Build.VERSION.SDK_INT (as JaKoZo showed).
With regard to the NFC settings, you could do even without that check and instead catch the exception that is thrown when no activity is registered for the ACTION_NFC_SETTINGS intent:
try {
this.startActivityForResult(
new Intent(android.provider.Settings.ACTION_NFC_SETTINGS),
1); // magic number to detect when this startActivityForResult returns
} catch (Exception e) {
try {
this.startActivityForResult(
new Intent(android.provider.Settings.ACTION_WIRELESS_SETTINGS),
1); // magic number to detect when this startActivityForResult returns
} catch (Exception e1) {
}
}
Instead of the constant ACTION_NFC_SETTINGS, you could also use the hard-coded string "android.settings.NFC_SETTINGS". While I don't really recommend this, you would not need to build against a higher API level (if it's only that constant that causes you to do so).
[...]
this.startActivityForResult(
new Intent("android.settings.NFC_SETTINGS"),
1); // magic number to detect when this startActivityForResult returns
[...]
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
//do stuff
}
u mean this?
I need to enable hardware acceleration on one of my WebViews. So far, I've found out that if I build my project with a target API of 11 or 13 (Android 3.0 and 3.2, respectively), hardware acceleration gets enabled and everything's fine. But the weird part is that when I build my project with API 17 or 18, all my efforts to turn on hardware acceleration get ignored for some reason.
So far I've tried:
1) Setting android:hardwareAccelerated="true" in my tag in the manifest
2) Same, but for the activity containing the WebView
3) The following code in my Activity's onCreate (before setting content view):
getWindow().setFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED, WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
4) The same, but using getWindow().addFlags(WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED);
In all cases, webView.isHardwareAccelerated() returns false, even when it's working.
Please help, it would be pretty lame to be stuck on API 13 because of this...
Tested on API 18:
Perform the check by posting a Runnable to the WebView:
WebView webView = (WebView) findViewById(R.id.webview_id);
// Shows: "Is hardware accelerated? false"
// Toast.makeText(YourActivity.this, "Is hardware accelerated? " +
// webView.isHardwareAccelerated(),
// Toast.LENGTH_LONG).show();
webView.post(new Runnable() {
#Override
public void run() {
Shows: "Is hardware accelerated? true"
Toast.makeText(YourActivity.this, "Is hardware accelerated? " +
webView.isHardwareAccelerated(),
Toast.LENGTH_LONG).show();
if (webView.isHardwareAccelerated()) {
// isAccelerated();
} else {
// isNotAccelerated();
}
}
});
From resource page on Hardware Acceleration:
Hardware acceleration is enabled by default if your Target API level
is >=14, but can also be explicitly enabled.
If the image you are displaying is still pixelated, try setting:
webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
and see if pixelation of the image gets better.
Consider reading the resource page on Hardware Acceleration.
I used the setLayerType method in my app to check the device hardwareAccelerated true or false, it's working on higher version (i.e 3+) but in lower version the app is crashing.
Here is my code snippet:
try {
if (android.os.Build.VERSION.SDK_INT > android.os.Build.VERSION_CODES.GINGERBREAD) {
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
} catch(Exception ex) {
}
I tried to check on AndroidManifest.xml but that doesn't work for me.
Api level check you have set is wrong. Change to
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.HONEYCOMB) {
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null);
}
The setLayerType() works only on Api 11 and above. And GINGERBREAD is Api 9 and GINGERBREAD_MR1 is Api 10.
I am using 1.6 i.e. API 4 to build my application. There are couple of commands that are supported by higher versions. I want to write those commands and make application more compatible for higher versons. Like, I use Tabs. I want to use setLeftStripDrawable and setRightStripDrawable, but they are supported by API 8.
I write something like :
// I want these lines to come into affect only if the device SDK is greater than 7 as SDK of below 7, doesn't support these methods.
if (android.os.Build.VERSION.SDK_INT > 7) {
tw.setLeftStripDrawable(R.drawable.tab_selected_bar_left_v4); // TabWidget
}
EDIT : I want to set setLeftStripDrawable to the tabs used in my app. In my manifest I have uses-sdk android:minSdkVersion="4". If I write the lines as above and compile it in 2.3, it compiles successfully. When I run in 1.6 I get "java.lang.VerifyError". If I remove those liens and again run in 1.6, it works properly.
What should I do to execute those lines only if the device SDK api is > 7, and if it is less than that then those lines should not come under any affect ?
Any clue ?
if (Build.VERSION.SDK_INT > 7) {
...
}
I think you should use something like this. I did this by heart, so there might be some errors.
try {
Method twMethod = TabWidget.class.getMethod("setLeftStripDrawable", new Class[] { int.class });
twMethod.invoke(tw, R.drawable.yourdrawable);
} catch (NoSuchMethodException e) {
/* not supported */
} catch (IllegalArgumentException e) {
/* wrong class provided */
} catch (IllegalAccessException e) {
/* Java access control has denied access */
} catch (InvocationTargetException e) {
/* method has thrown an exception */
}
You can try looking at Android Reflection. I have not used it yet myself, but as far as i understand, you can test for classes and methods that you know the name of. Then you can instantiate and use them.
You can read some of the basics here: http://www.tutorialbin.com/tutorials/85977/java-for-android-developers-reflection-basics
Here's some sample Android code, using reflection, that does something similar. It calls the getRotation() method from the Display class; the method only exists in SDK 8+. I've used it in one of my apps and it works:
//I want to run this: displayrotation = getWindowManager().getDefaultDisplay().getRotation();
//but the getRotation() method only exists in SDK 8+, so I have to call it in a sly way, using Java "reflection"
try{
Method m = Display.class.getMethod("getRotation", (Class[]) null);//grab the getRotation() method if it exists
//second argument above is an array containing input Class types for the method. In this case it takes no inputs.
displayrotation = (Integer) m.invoke(getWindowManager().getDefaultDisplay(),(Object[]) null);
//again, second argument is an array of inputs, in this case empty
}catch(Exception e){//if method doesn't exist, take appropriate alternate actions
Log.w("getRotation","old OS version => Assuming 90 degrees rotation");
displayrotation = Surface.ROTATION_90;
}