How do you detect if user has auto-brightness enabled? - java

It should be an easily searchable question yet I can't find a single result. I can find how to retrieve screen brightness but not how to retrieve the status of auto brightness.
And a second question, Android Studio forces me to surround this statement with a try/catch block, which I guess means it won't work all the time. Is there a more reliable way to retrieve screen brightness?
int currentBrightness = Settings.System.getInt(getContext().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
When I hover the mouse over getInt I get this message: Unhandled exception: android.provider.Settings.SettingNotFoundException
I have to turn it into this:
try {
int currentBrightness = Settings.System.getInt(getContext().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS);
} catch (Settings.SettingNotFoundException e) {
e.printStackTrace();
}

how to retrieve the status of auto brightness
If you Ctrl+click SCREEN_BRIGHTNESS in Android Studio you can see the source code. Right below where SCREEN_BRIGHTNESS is there's also SCREEN_BRIGHTNESS_MODE and constants for the two modes:
/** Control whether to enable automatic brightness mode. */
public static final String SCREEN_BRIGHTNESS_MODE = "screen_brightness_mode";
/** SCREEN_BRIGHTNESS_MODE value for manual mode. */
public static final int SCREEN_BRIGHTNESS_MODE_MANUAL = 0;
/** SCREEN_BRIGHTNESS_MODE value for automatic mode. */
public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1;
See also Settings.java in Android Code Search.
Android Studio forces me to surround this statement with a try/catch block, which I guess means it won't work all the time.
Android Studio doesn't force you to do anything, it's trying to tell you something, probably, that you should do something differently. At the minimum, log the exception so you can share it in your SO question, so people can help you figure out what's going on.
Update your question with the exact exception stack trace and more code.
android.provider.Settings.SettingNotFoundException
SettingNotFoundException happens in getInt when
the setting is unset
the setting set but is not a number
If you don't want to deal with it use the overload that takes 3 parameters and doesn't throw:
ContentResolver contentResolver = getContext().getContentResolver();
int currentBrightness = Settings.System.getInt(contentResolver, Settings.System.SCREEN_BRIGHTNESS, /* default value */ 0);
Per documentation:
The default value will be returned if the setting is not defined or not an integer.

If you want to know if the user has the auto brightness mode enabled in the device, you can try a function like that:
int getBrightnessMode() {
try {
int brightnessmode = Settings.System.getInt(getContentResolver(), Settings.System.SCREEN_BRIGHTNESS_MODE);
return brightnessmode;
} catch (Exception e) {
return 0;
}
}
This function will return a number, 1 for auto brightness enabled and 0 for auto brightness disabled.
If you want to change the brightness manually, your app needs a special permission, because the screen brightness is a device parameter.
To give permission to the app and change the brightness, use this code:
if (!Settings.System.canWrite(getApplicationContext())) {
Intent intent = new Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS);
startActivity(intent);
}
if (Settings.System.canWrite(getApplicationContext())) {
Settings.System.putInt(getApplicationContext().getContentResolver(), Settings.System.SCREEN_BRIGHTNESS, myBrightness);
}
You will need to add the Write Settings permission to the AndroidManifest file:
<uses-permission android:name="android.permission.WRITE_SETTINGS"
tools:ignore="ProtectedPermissions" />

Tested on Nokia 6.2 & Samsung Tab Running Android 10 and Android 5.1
private int getMobileBrightnessMode() {
// works for adaptive brightness option as well as auto for old models
// adaptive brighness Android Pie onwards
// Auto Brightness for old versions
ContentResolver contentResolver = getContentResolver();
int brightnessMode = 0;
try {
brightnessMode = Settings.System.getInt(contentResolver,Settings.System.SCREEN_BRIGHTNESS_MODE);
} catch (Exception e) {
Log.d("tag", e.toString());
}
return brightnessMode;
// if 0 auto mode is off
// if 1 auto mode is on
}

Related

Java Android Badge Drawable not working properly after configuration change

I have a Bottom Navigation view with a badge drawable that shows new chats.
This badges are updated upon a listener to Firebase database, where I store the notification counter. When this value change, the badge is updated. Moreover if the counter is equal to zero, the badge is set not visible.
Everything works fine except if I change some configuration using the device Settings (such as language or removing permissions). In fact, if I do that and go back to the app, the activity is re-created (sometimes without destroying it) and badge reloaded. But the setVisibility seems not working. Even if the counter is zero the badge is visible. Plus is not update anymore when the listener is triggered.
The code works, I checked with some logs if the listener is triggered and if the lines which include setVisibility are run. It just seems to have random behaviour.
If the activity is destroyed and recreated again, it works.
Any help will be appreciated!
this is how I initialize the badge
bottomNav = findViewById(R.id.bottom_navigation);
badge_chat = bottomNav.getOrCreateBadge(R.id.nav_chat);
badge_chat.setVisible(false);
this is the listener code
public void onChildChanged(#NonNull DataSnapshot dataSnapshot, #Nullable String s) {
int badge_counter = dataSnapshot.getValue(int.class);
boolean visibility;
if (badge_counter == 0) {
visibility = false;
} else {
visibility = true;
}
badge_chat.setNumber(badge_counter);
badge_chat.setVisible(visibility);
}
One way I've managed to resolve this is to create/remove badge whenever it needs to be visible/hidden. In your case, something like this should work:
if (badge_counter == 0) {
getBadge(R.id.nav_chat)?.isVisible = false
removeBadge(R.id.nav_chat)
} else {
getOrCreateBadge(R.id.nav_chat).apply{
isVisible = true
number = badge_counter
}
}
note: the answer is in Kotlin.

weird phenomenon about android Debugger (CloseableReference)

There I have a loop:
public void updateDrawee(View view) {
if (begin) {
begin = false;
for (int i = 0; i < 5; i++) {
CloseableReference<CloseableImage> reference = createBitmapRefer(i);
Log.i("reference", reference+"");
imgList.add(reference);
}Log.i("imgList", imgList.toString());Log.i("imgList.0", imgList.get(0)+"");
}
//...some code
}
and the method createBitmapRefer(int count) follow:
public CloseableReference<CloseableImage> createBitmapRefer(int count) {
ImagePipeline pipeline = Fresco.getImagePipeline();
int[] drawableIds = {R.drawable.alpha1, R.drawable.alpha2,
R.drawable.alpha3, R.drawable.alpha4, R.drawable.alpha5};
ImageRequest levelRequest
= ImageRequestBuilder.newBuilderWithResourceId(drawableIds[count])//++
.setProgressiveRenderingEnabled(true)//逐行加载
.build();
CloseableReference<CloseableImage> bmpReference = null;
DataSource<CloseableReference<CloseableImage>> dataSource
= pipeline.fetchImageFromBitmapCache(levelRequest, this);
try {
if (!dataSource.hasResult()) {
dataSource = pipeline.fetchDecodedImage(levelRequest, this);
}
//count %= 5;
Log.i("dataSource has result", dataSource.hasResult() +"");
Log.i("dataSource fail?", dataSource.hasFailed() + "");
bmpReference = dataSource.getResult();
Log.i("bmpRefer", bmpReference+"");
if (bmpReference != null) {
CloseableReference<CloseableImage> returnRef;
returnRef = bmpReference.clone();
return returnRef;
}else {
return null;
}
}finally {
dataSource.close();
CloseableReference.closeSafely(bmpReference);
}
}
when I debug, if i click step into and see the code step by step, it will return a CloseableReference just as I want, and the imgList(its a ArrayList) can get the element too.BUT if I step over the for loop, it return nothing!
Is there any different between keep looking at it or not???
the watches show elements in imgList, when index=1 and 4, I clicked step into.
and the logcat show what Log.i() print.
Or because I have not use this classCloseableReference in Standardized way?
Let me try to explain what happens here.
You are not using Fresco in the intended way. I will step back for a moment and strongly suggest that you use SimpleDraweView if you just need to display images. If however you really need the underlying bitmap, you can get it from the ImagePipeline in way similar to what you already doing, but with one key difference. Fetching images happens asynchronously. What that means is that you can't just do dataSource = pipeline.fetchDecodedImage(...) and then immediately dataSource.getResult. If the image was not found in the memory cache, getResult will just return null. What you need to do instead is to subscribe to the DataSource as explained in the Fresco documentation. I strongly suggest that you read those few chapters about ImagePipeline if you intend to use it directly. Otherwise you may cause your app to leak the memory or to crash because of rendering recycled bitmap.
What you see in debugger is exactly what I described above. The array of size 5 looks like this:
0 = null,
1 = CloseableReference#4908,
2 = null,
3 = null,
4 = CloseableReference#5231
The AndroidStudio UI just hides the null entries for brevity. You can turn this off if you don't like it by right-clicking there and opening options. The reason you get something for 1 and 4 is because the image has been found in the bitmap memory cache and was retrieved from it immediately. The reason you get null for 0, 2 and 3 is because the image has not been loaded yet. Fresco might need to download the image, and even if it is already downloaded and in the disk cache, it may need to decode the image. All of this takes some time and is not instantaneous. That's why you need to subscribe your callback and ImagePipeline will notify you when the image is ready.

Check for navigation bar

I am trying to check to see whether the android navigation bar is present on load so that I can adjust a layout accordingly, does anyone have any suggestions?
This is the navigation bar I am trying to detect:
P.S. All I have found so far are 'bad' ways to try and remove the bar, which I dont want to do.
Took me some time but I've found a more reliable way than relying on hasPermanentMenuKey() which doesn't work for newer phones like the HTC One which have no menu key but do have home & back keys so don't need (or show) the soft navigation bar. To get around this try the following code which checks for a back button too:
boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
if(!hasMenuKey && !hasBackKey) {
// Do whatever you need to do, this device has a navigation bar
}
There's no reliable way to check for a navigation bar. Using KeyCharacterMap.deviceHasKey you can check if certain physical keys are present on the device, but this information is not very useful since devices with physical keys can still have a navigation bar. Devices like the OnePlus One, or any device running a custom rom, have an option in the settings that disables the physical keys, and adds a navigation bar. There's no way to check if this option is enabled, and deviceHasKey still returns true for the keys that are disabled by this option.
This is the closest you can get:
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
boolean hasHomeKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_HOME);
if (hasBackKey && hasHomeKey) {
// no navigation bar, unless it is enabled in the settings
} else {
// 99% sure there's a navigation bar
}
If the back and home button are not both physically present on the device, it must have a navigation bar, because the user otherwise wouldn't be able to navigate at all. However, you can never be 100% sure about this, since manufacturers can implement deviceHasKey wrong.
Another solution
(a part of my class UtilsUISystem )
public static boolean hasNavBar (Resources resources)
{
//Emulator
if (Build.FINGERPRINT.startsWith("generic"))
return true;
int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
return id > 0 && resources.getBoolean(id);
}
Here is a quick answer that combines Pauland's and Philask's solutions. I'm afraid I don't have enough devices available to test if it works everywhere, though. I'd be interested to hear others' results.
boolean hasNavBar(Context context) {
Resources resources = context.getResources();
int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
if (id > 0) {
return resources.getBoolean(id);
} else { // Check for keys
boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
return !hasMenuKey && !hasBackKey;
}
}
I've done like this, it works on every device I tested, and even on emulators:
public static boolean hasNavigationBar(Activity activity) {
Rect rectangle = new Rect();
DisplayMetrics displayMetrics = new DisplayMetrics();
activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(rectangle);
activity.getWindowManager().getDefaultDisplay().getRealMetrics(displayMetrics);
return displayMetrics.heightPixels != (rectangle.top + rectangle.height());
}
you could add this code to your activity's onCreate() method:
View decorView = getWindow().getDecorView();
decorView.setOnSystemUiVisibilityChangeListener
(new View.OnSystemUiVisibilityChangeListener() {
#Override
public void onSystemUiVisibilityChange(int visibility) {
if ((visibility & View.SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
// TODO: The navigation bar is visible. Make any desired
// adjustments to your UI, such as showing the action bar or
// other navigational controls.
} else {
// TODO: The navigation bar is NOT visible. Make any desired
// adjustments to your UI, such as hiding the action bar or
// other navigational controls.
}
}
});
This method worked for me
int id = getResources().getIdentifier("config_showNavigationBar","bool","android");
boolean result = id > 0 && getResources().getBoolean(id);
//
if(result) {
// Do whatever you need to do, this device has a soft Navigation Bar
}
It worked for me and tested in many devices.
Something that should probably work better is to measure the screen.
Starting with API 17 there's getWindowManager().getDefaultDisplay().getRealSize(), which can be compared to size returned by getWindowManager().getDefaultDisplay().getSize().
If you get different results I think it's safe to say that there is a nav bar and if you get the same results there isn't one. One thing to pay attention to is your target SDK and supported screens, which might cause the result of getSize() to be scaled if Android thinks your app wouldn't work well on the current device without scaling.
Below API 17 you can measure the screen via getWindowManager().getDefaultDisplay().getMetrics() in both landscape and portrait mode, and again, different results probably mean there's a nav bar.
However, if you get the same results, you don't actually know, as phones can keep the nav bar on the shorter edge even when in landscape. An educated guess would be that if either the width or the height is 4% to 8% smaller than standard sizes like 1280x800, 1280x720, 1024x600, while the other dimension is equal, then again there probably is a nav bar. Don't bet on it, though. There are too many resolutions, which differ too little from one another for this to work well.
boolean hasNavBar(Context context) {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
// navigation bar was introduced in Android 4.0 (API level 14)
Resources resources = context.getResources();
int id = resources.getIdentifier("config_showNavigationBar", "bool", "android");
if (id > 0) {
return resources.getBoolean(id);
} else { // Check for keys
boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();
boolean hasBackKey = KeyCharacterMap.deviceHasKey(KeyEvent.KEYCODE_BACK);
return !hasMenuKey && !hasBackKey;
}
} else {
return false;
}
}
On Android 10 (API level 29), you can also check for the bottom window inset:
#RequiresApi(api = Build.VERSION_CODES.Q)
private boolean hasNavigationBar() {
final WindowInsets windowInsets = getWindow().getDecorView().getRootWindowInsets();
if (windowInsets == null) {
throw new RuntimeException("Window is not attached");
}
return windowInsets.getTappableElementInsets().bottom > 0;
}
Note that the window has to be attached for getRootWindowInsets() to return a non-null value, so you likely want to call this in onAttachedToWindow.
This solution is also used by LineageOS's launcher app Trebuchet (source), which is how I learned of it.
I see the answers above, I want to indicate
that the "not exist" can be regard as the height of 0;
so it can be like this:
public static int getScreenH(Context context) {
DisplayMetrics dm = new DisplayMetrics();
dm = context.getResources().getDisplayMetrics();
int h = dm.heightPixels;
return h;
}
public static int getDpi(Context context) {
DisplayMetrics displayMetrics1 = context.getResources().getDisplayMetrics();
int height1 = displayMetrics1.heightPixels;
int dpi = 0;
WindowManager windowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
Display display = windowManager.getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
#SuppressWarnings("rawtypes")
Class c;
try {
c = Class.forName("android.view.Display");
#SuppressWarnings("unchecked")
Method method = c.getMethod("getRealMetrics", DisplayMetrics.class);
method.invoke(display, displayMetrics);
dpi = displayMetrics.heightPixels;
} catch (Exception e) {
e.printStackTrace();
}
return dpi;
}
public static int getBottomStatusHeight(Context context) {
int totalHeight = getDpi(context);
int contentHeight = getScreenH(context);
return totalHeight - contentHeight;
}
```
Solution: Only devices without permanent hardware keys have the navigation bar hence you can check for the API version and use hasPermanentMenuKey() to find hardware keys
boolean hasMenuKey = ViewConfiguration.get(context).hasPermanentMenuKey();

Is there a system variable that holds the device-specific low-battery threshold for Android?

I am checking to see if the battery has reached critical level.
Android sends an intent to your app when the battery crosses the low-battery threshold in either direction. But this only works if the threshold is crossed while your app is running (the intent is not sticky, so it doesn't hang around). So if it's low when the user opens the app, you're out of luck (or at least information).
There is also a sticky intent, ACTION_BATTERY_CHANGED, that has information about the battery level and a scale for calculating percentages, which is great. However, I have been unable to find the system variable that contains the low-battery threshold (it apparently varies across device).
Doing a search, I found: When android fires ACTION_BATTERY_LOW, a source listing of Android system code, which uses the system variable com.android.internal.R.integer.config_lowBatteryWarningLevel. However, I have been unable to access this variable myself (my guess is that it is protected).
I would like to have a reasonable standard to compare my battery percentage to, so I know when to turn off battery-intensive functionality. That is all.
Here is my code:
private BroadcastReceiver powerListener = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
int batteryLevel = intent.getIntExtra(BatteryManager.EXTRA_LEVEL, 0);
int batteryScale = intent.getIntExtra(BatteryManager.EXTRA_SCALE, 1);
int batteryPercentLeft = (batteryLevel * 100) / batteryScale;
if (batteryPercentLeft <= com.android.internal.R.integer.config_lowBatteryWarningLevel) {
_thread.onBatteryStateReceived(DataModel.BatteryState.LOW);
}
}
};
I get a compile error for the system variable. Is there an alternative? It seems like this should be a straightforward thing to do. I just want to match system behavior, nothing fancy.
Note that this is possible, but uses reflection so should not be relied upon:
try {
Class clazz = Class.forName("com.android.internal.R$integer");
Field field = clazz.getDeclaredField("config_lowBatteryWarningLevel");
field.setAccessible(true);
int LowBatteryLevel = _context.getResources().getInteger(field.getInt(null));
Log.d("LowBattery","warninglevel " + LowBatteryLevel);
} catch (ClassNotFoundException | NoSuchFieldException | IllegalAccessException e) {
e.printStackTrace();
}
Source: https://stackoverflow.com/a/49424298/608312

Face detection not working for Front Camera

So basically, i have this code,
if(mCamera.getParameters().getMaxNumDetectedFaces()==0)
{
System.out.println("Face detection not avaliable");
}
else
{
System.out.println("Max faces: " + Integer.toString(mCamera.getParameters().getMaxNumDetectedFaces()));
}
mCamera.setFaceDetectionListener(new FaceDetectionListener() {
#Override
public void onFaceDetection(Face[] faces, Camera camera) {
// TODO Auto-generated method stub
System.out.println("Face detection callback called." + Integer.toString(faces.length));
}
});
After calling mCamera.startFaceDetection();, the callback is called, everything works as normal. However, if I change cameras, the same code results in the callback never being called. The getMaxNumDetectedFaces, returns 35 for both cameras, so I assume its supported on the front camera. I can change the camera back and forth, calling this code each time, and it will work for the back camera but not the front one.
Is there anything else I might be doing wrong?
Is it possible that the quality of the camera that's not working (the front one, right?) Isn't accurate enough for the face detection to work? The camera's image may be too noisy for the face detector to work. There are lot of other variables that could be hindering this.
Also doing a search for front camera, it looks like the front camera's points may be mirrored. This is described in: http://developer.android.com/reference/android/hardware/Camera.Face.html
I hope this helps.
Is there a way to check if the camera is being read? Java has always had some issues in registering web cams etc.... Perhaps try to make sure you can see images with the webcam.
Btw, if you want any further help, we will need to know more about the code. library etc....
This code will return the id of your Front facing camera, for others you can change camera.CameraInfo:
private int findFrontFacingCamera() {
int cameraId = -1;
// Search for the front facing camera
int numberOfCameras = Camera.getNumberOfCameras();
for (int i = 0; i < numberOfCameras; i++) {
Camera.CameraInfo info = new Camera.CameraInfo();
Camera.getCameraInfo(i, info);
if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
Log.d("FaceDetector", "Camera found");
cameraId = i;
break;
}
}
return cameraId;
}
I had the code which worked on my Gallaxy tablet but it wouldnt call the take foto and as a result wouldnt call face detection in other devices, so after searching for a while I found this solution which worked. I added the following code in the class where takePicture is called :
camera.startPreview();
You can use Webcame for capturing image from webcam. it automatically detects webcam so no need to extra configuration for webcam. it also support more than one webcam at a time.

Categories

Resources