To enable WebView debugging based on the debuggable flag, Google recommends the following code:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE)) {
WebView.setWebContentsDebuggingEnabled(true);
}
}
Doesn't this have side effects, since the &= operator reassigns the flag field? I am assuming the application flags are reduced to FLAG_DEBUGGABLE after this call. Why would you want the &= operator here instead of &?
Yep, it's a bug in documentation. The code is broken. It does indeed strip out any flags from ApplicationInfo.flags other than FLAG_DEBUGGABLE. The correct check is getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE. This check does not modify the flags field.
No, &= means getApplicationInfo().flags = getApplicationInfo().flags & ApplicationInfo.FLAG_DEBUGGABLE which just sets that flag from 0 to 1.
It is just like += or |= which shortens the expression a bit.
All existing flags will be kept.
Related
The code I want to use:
window.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED)
There is FLAG_SHOW_WHEN_LOCKED that is deprecated in the API 27 and its alternative setShowWhenLocked added in the API 27
How should I use it properly if the minSdk in my project is 21 and the targetSdk is 33?
I get the warning is deprecated. Deprecated in Java
Even if I handle it this way:
if(Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
}
I still get the warning. What is the right way to support both old and new API?
TLDR
1.Use different code for different API versions.
2.Ignore/surpress this warning if you properly proccess all the API versions that your app is created for
3.If there is a new alternative that works for all the API levels - use it
Instruction
Use Build.VERSION.SDK_INT in the condition to behave accordingly to the SDK_INT
Use setshowwhenlocked if SDK_INT>=27 and FLAG_SHOW_WHEN_LOCKED if SDK_INT<27
Surpress the warning
Example with the FLAG_SHOW_WHEN_LOCKED/setShowWhenLocked
if(Build.VERSION.SDK_INT >= 27) {
setShowWhenLocked(true)
setTurnScreenOn(true)
} else {
#Suppress("DEPRECATION")
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
}
But why do we have to surpsess the warning?
The warning exists only because #Deprecated APIs do not have any metadata that would indicate which SDK they were deprecated in. as you can see in this issue.
We can surpress the error because we have properly processed both old api (5-27) and new api (27>)
Warning
Do not surpress these warnings if the code is not properly processed by using if conditions where the right API is used.
Example how you must not do
#Suppress("DEPRECATION")
window.addFlags(WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD or
WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED or
WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON)
Your minSdk is 21 and targetSdk is 33
This code will work on devices with 5-27 API (Android 5 - Android 8.1) but will not work on new devices. You must properly handle both conditions.
Example with the Vibrator
The old way to get the vibrator
context.getSystemService(VIBRATOR_SERVICE) as Vibrator
The new way to get the vibrator
val vibrator = if (Build.VERSION.SDK_INT >= 31) {
val vibratorManager =
context.getSystemService(Context.VIBRATOR_MANAGER_SERVICE) as VibratorManager
vibratorManager.defaultVibrator
} else {
#Suppress("DEPRECATION")
context.getSystemService(VIBRATOR_SERVICE) as Vibrator
}
Will show you the warning `'VIBRATOR_SERVICE: String' is deprecated. Deprecated in Java`. Go to the [documentation](https://developer.android.com/reference/kotlin/android/content/Context#vibrator_service) and see that this constant can be used in the API 1-31 so we must. And in both IDE and documentation there is the info about the alternative: `Deprecated: Use android.os.VibratorManager to retrieve the default system vibrator.`. As you can see the [VibrationManager](https://developer.android.com/reference/kotlin/android/os/VibratorManager) is added in the API 31 therefore we must write the different code for different sdk versions
If an alternative is backwards compatible
If an alternative is backwards compatible you can just use it instead of the old way
Example
If you inherit AppCompatActivity in your activity:
class SaveMyLifeActivity : AppCompatActivity()
You can meet the warning startActivityForResult(Intent!, Int): Unit' is deprecated. Deprecated in Java if you call startActivityForResult:
val intent = Intent(this, SaveMyLifeActivity::class.java)
startActivityForResult(intent, 0)
You can press Alt+Q (Default keybind) to see the Context info(it is called this way in the AndroidStudio is you check your keymap) or use the website do see the documentation
Take a look to the words that this method is deprecated and you must use registerForActivityResult instead. This method can be called in any version right now, there are no Added/Deprecated "section" in the documentation.
Question: How have you found this documentation? I google AppCombatActivity startActivityForResult and come to this documentation. There is no word about startActivityForResult.
Answer: Open the context info about this method in the IDE (Alt+Q) and look at the bottom of the Context info . There is a class name where this method is located in (ComponentActivity). You have to google ComponentActivity startActivityForResult instead of AppCombatActivity startActivityForResult
I am having a webApp that loads in a webView. I don't want remote debugging to be enabled on the webview.
I have read several blogs and unable to find any related to this query. Can someone provide any pointer on this.
Appreciate your help!!!
allow only for build debug then
if (BuildConfig.DEBUG) {
WebView.setWebContentsDebuggingEnabled(true);
}
or
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
if (0 != (getApplicationInfo().flags &= ApplicationInfo.FLAG_DEBUGGABLE))
{ WebView.setWebContentsDebuggingEnabled(true); }
}
( The default is false.)
source :
Documentation
Java Documentation
Is there any way to uncheck the option "Do not keep activities " from developer settings in the code of my application? I want to check the status and uncheck this option for my application. Is this possible?
You should not rely on that setting, activities can be destroyed even if that setting is turned off (for instance, if the device is running low on memory).Also, you can not disable / enable the setting programatically.
You can, however, check if the setting is turned on, with this code:
boolean enabled;
if (Build.VERSION.SDK_INT >= 17) {
enabled = Settings.System.getInt(context.getContentResolver(), Settings.System.ALWAYS_FINISH_ACTIVITIES, 0) == 1;
} else {
enabled = Settings.Global.getInt(context.getContentResolver(), Settings.Global.ALWAYS_FINISH_ACTIVITIES, 0) == 1;
}
This is how I handle a deprecated method:
int layoutDirection ;
if (getContext().getApplicationInfo().targetSdkVersion > Build.VERSION_CODES.JELLY_BEAN_MR1) {
layoutDirection = getLayoutDirection();
}else {
layoutDirection = getResolvedLayoutDirection();
}
The problem is that getResolvedLayoutDirection() has been removed at JELLY_BEAN_MR1 and above. So since my project targets API 20 the method cannot be found and I get an error.
If I keep it foolish:
int layoutDirection = getLayoutDirection();
The project compiles and runs but still I get an error to add either the TargetApi or SuppressLint annotation. getLayoutDirection() docs have:
For compatibility, this will return {#link #LAYOUT_DIRECTION_LTR} if
API version is lower than {#link
android.os.Build.VERSION_CODES#JELLY_BEAN_MR1}.
So suppressing lint should be fine.
Should I suppress the lint error or fix it somehow else (possibly make getResolvedLayoutDirection() accessible)?
The approach to conditionally check whether a method is available is to check the version of Android that the device is running, via Build.VERSION.SDK_INT:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
layoutDirection = getLayoutDirection();
}
else {
layoutDirection = View.LAYOUT_DIRECTION_LTR;
}
And add #TargetApi(Build.VERSION_CODES.JELLY_BEAN_MR1) to the method containing the above block to indicate to the build tools that, for that individual method, to consider your minSdkVersion to be 17 instead of whatever it normally is, for the purposes of generating Lint warnings and errors.
Issue
Finding methods to toggle between:
Always
Never
Only in Silent Mode
Only When Not in Silent Mode
These choices are found by the path --- Menu >> Settings >> Sound >> Vibrate --- on the phone.
It is simple to change by navigation on the phone (by the way, my phone is a Motorola Atrix 2 with Android 2.3.3), but I have yet to come across methods to use in my code.
Code
I basically have buttons that should manipulate the vibrate settings when clicked. One of these buttons is shown here:
bSilent.setOnClickListener(new View.OnClickListener()
{
public void onClick(View v)
{
audioManager.setRingerMode(AudioManager.RINGER_MODE_SILENT);
audioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
audioManager.setVibrateSetting(AudioManager.VIBRATE_TYPE_NOTIFICATION, AudioManager.VIBRATE_SETTING_OFF);
Toast.makeText(getBaseContext(), "Set to Never", Toast.LENGTH_SHORT).show();
}
});
audioManager is defined somewhere above this code as:
final AudioManager audioManager = (AudioManager) this.getSystemService(Context.AUDIO_SERVICE);
Android offers the AudioManager.setVibrateSetting, but it is now deprecated. Instead, they reference you to the getRingerMode method.
http://developer.android.com/reference/android/media/AudioManager.html
However, using these functions (and any combination of them) do not efficiently move between the four vibrate settings. For example, if I start at "Always", it is seemingly impossible for me to get to "Never". All combinations of vibrate methods will only move between "Always" and "Only in Silent Mode". On the other hand, if I start at "Never", the offered methods will only toggle between "Never" and "Only When Not in Silent Mode".
Therefore, suppose I want to have my phone in silent mode and want it to vibrate. Then, I decide I do not wish it to vibrate any longer. I am unable to switch from "Always" or "Only in Silent Mode" to "Never".
Past Solutions and Posts
I am aware that this is somewhat of a duplicate post on StackOverflow. The issue has been brought up before...
Here: Vibrate settings on Android 2.2
And (more recently) here: Changing vibrate setting
The former of the links provides an "answer". LuTHieR ends up in a discussion and eventually figures out a way on his own. He references the site:
https://android.googlesource.com/platform/packages/apps/Settings/+/froyo-release/src/com/android/settings/SoundSettings.java
and says "I looked at the source code of the com.android.settings.Settings class and copied part of the methods that enable and disable vibrate".
I looked through this site vigorously and could not find what he did. Could anyone clarify his solution?
Question
Does anyone have a way to precisely toggle between "Always", "Never", "Only in Silent Mode", and "Only When Not in Silent Mode"?
My solution (path of the function with income String sParam with needed mode of vibration set, refactoring if need to integer 0-3):
AudioManager audioManager = getSystemService( Context.AUDIO_SERVICE);
if( Build.VERSION.SDK_INT < 16)
{
// sParam may be:
// 0 - Always
// 1 - Never
// 2 - Only in silent mode (when sound is off)
// 3 - Only when not in silent mode (when sound is on)
if( (sParam.equals( "1") == true) || (sParam.equals( "3") == true))
{
Settings.System.putInt( Static.contextApplication.getContentResolver(), "vibrate_in_silent", 0);
if( sParam.equals( "1") == true)
audioManager.setVibrateSetting( AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_OFF);
if( sParam.equals( "3") == true)
audioManager.setVibrateSetting( AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ON);
}
if( (sParam.equals( "0") == true) || (sParam.equals( "2") == true))
{
Settings.System.putInt( Static.contextApplication.getContentResolver(), "vibrate_in_silent", 1);
if( sParam.equals( "0") == true)
audioManager.setVibrateSetting( AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ON);
if( sParam.equals( "2") == true)
audioManager.setVibrateSetting( AudioManager.VIBRATE_TYPE_RINGER, AudioManager.VIBRATE_SETTING_ONLY_SILENT);
}
}
// else (for new SDK > 16 via setRingerMode() ??? )