Allow sound while UserManager.DISALLOW_ADJUST_VOLUME user permission is active - android

I'm building an application for a COSU device. I based my code on the following example provided by Google:
Codelabs.developers.google.com/cosu
In the LockedActivity there is the following piece of code:
private void setDefaultCosuPolicies(boolean active){
// Set user restrictions
setUserRestriction(UserManager.DISALLOW_SAFE_BOOT, active);
setUserRestriction(UserManager.DISALLOW_FACTORY_RESET, active);
setUserRestriction(UserManager.DISALLOW_ADD_USER, active);
setUserRestriction(UserManager.DISALLOW_MOUNT_PHYSICAL_MEDIA, active);
setUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME, active);
// remainder of this method is left out for simplicity
}
private void setUserRestriction(String restriction, boolean disallow){
if (disallow) {
mDevicePolicyManager.addUserRestriction(mAdminComponentName,
restriction);
} else {
mDevicePolicyManager.clearUserRestriction(mAdminComponentName,
restriction);
}
}
When active == true in the above snippet, the volume buttons are disabled correctly as a consequence of setUserRestriction(UserManager.DISALLOW_ADJUST_VOLUME, true). However, this also mutes the master volume (which is documented here). That prevents my application from playing any sound. Personally, I think it would be better if the volume would simply be frozen at the level it was or if the volume were at least programmatically still configurable (which seems not to be the case).
I could programmatically override the volume up/down buttons, but that feels more like a workaround/hack (this is for instance done here).
So my question is: Is there a way to unmute the master volume while having the UserManager.DISALLOW_ADJUST_VOLUMEuser permission set to true? Or are there any decent workarounds?

Related

What is rate limiting for android app shortcuts?

As per documentation for app shortcuts
Rate Limiting
When using the setDynamicShortcuts(), addDynamicShortcuts(), or
updateShortcuts() methods, keep in mind that you might only be able to
call these methods a specific number of times in a background app, an
app with no activities or services currently in the foreground. In a
production environment, you can reset this rate limiting by bringing
your app to the foreground.
What is rate limiting in concern with app shortcuts? when isRateLimitingActive() should be used?
Looking at the source code it seems that the isRateLimitingActive() method returns false if you do not have any remaining calls left to the ShortcutManager API (hence the "0"). I guess rate limiting is needed because the API is resource intensive. I can imagine that at least the following will happen if you update a shortcut:
The launcher app (and other listeners) needs to be notified and starts updating it's UI or whatever is needed (depends on the launcher);
The system needs to store the new dynamic shortcut information;
You could use this method to find out if a call to setDynamicShortcuts(), addDynamicShortcuts() or updateShortcuts() will succeed before even trying to do so.
Source:
/**
* Return {#code true} when rate-limiting is active for the caller application.
*
* <p>See the class level javadoc for details.
*
* #throws IllegalStateException when the user is locked.
*/
public boolean isRateLimitingActive() {
try {
return mService.getRemainingCallCount(mContext.getPackageName(), injectMyUserId())
== 0;
} catch (RemoteException e) {
throw e.rethrowFromSystemServer();
}
}
Bonus: setDynamicShortcuts(), addDynamicShortcuts() or updateShortcuts() return false if they did not succeed due to Rate Limiting.
The recommended maximum number of shortcuts is 4, although it is possible to publish up to 5. You can read more here.

Setting sound configuration for Socket device

Using the following code to attempt setting the sound on/off for a Socket 8ci...not quite working for me. Can you suggest a proper command? As you can see in the code I set the Sound frequency based on a preference boolean. Thanks!
DeviceInfo device = (DeviceInfo) _scanApiHelper.getDevicesList().lastElement();
short[] soundConfig = new short[3];
// default the sound to On
if(getBRSharedPreferenceBoolean(PreferencesActivity.PREF_SOCKET_SCANNER_BEEP, true)) {
soundConfig[0] = ISktScanProperty.values.soundFrequency.kSktScanSoundFrequencyHigh;
} else {
soundConfig[0] = ISktScanProperty.values.soundFrequency.kSktScanSoundFrequencyNone;
}
soundConfig[1] = 200;
soundConfig[2] = 100;
// set the scanner sound config
_scanApiHelper.postSetSoundConfigDevice(
device,
ISktScanProperty.values.soundActionType.kSktScanSoundActionTypeGoodScan,
soundConfig,
_onSetScanApiConfiguration);
The Problem
Sound Config Device
The sound config allows you to set 4 different "actions": kSktScanSoundActionTypeGoodScan, kSktScanSoundActionTypeGoodScanLocal, kSktScanSoundActionTypeBadScan, kSktScanSoundActionTypeBadScanLocal. The difference between GoodScan and BadScan is self-explanatory, but the difference between GoodScan and GoodScanLocal isn't very clear.
GoodScanLocal, by default, is the sound emitted when a barcode is scanned
GoodScan is only emitted when the host (e.g. Android, iOS, Windows) sends the scanner a GoodScan or BadScan notification (via kSktScanPropIdDataConfirmationDevice)
Note: If you are using GoodScan/BadScan to verify decoded data, you probably want to change the confirmation mode (see kSktScanPropIdDataConfirmationMode in the docs). Otherwise the scanner will beep/flash/vibrate twice per scan
The code snippet your snippet is based on uses the latter to demonstrate that the tone is both configurable and can be triggered by the host.
You select a tone, hit the confirm button and the scanner emits that tone. It's not clear at first glance, but if you change the tone using the dropdown in SingleEntry and hit confirm, the three tones are very distinct. However, if you change the tone using that same dropdown, the tone you hear when you scan a barcode should not change.
The Solution
The best and simplest way to achieve what you are trying to achieve is to set the Local Decode Action with the beep disabled
Local Decode Action
// import static com.socketmobile.scanapi.ISktScanProperty.values.localDecodeAction.*;
DeviceInfo device = (DeviceInfo) _scanApiHelper.getDevicesList().lastElement();
int decodeAction = kSktScanLocalDecodeActionFlash | kSktScanLocalDecodeActionRumble;
if(getBRSharedPreferenceBoolean(PreferencesActivity.PREF_SOCKET_SCANNER_BEEP, true)) {
decodeAction |= kSktScanLocalDecodeActionBeep;
}
_scanApiHelper.postSetDecodeAction(device, decodeAction)
For completeness sake, to achieve a similar result using the code you posted, you'd only need to change kSktScanSoundActionTypeGoodScan to kSktScanSoundActionTypeGoodScanLocal. Although I would not recommend it.

Disable Rematch in Google Play Games

I use Google Play Games Services and everythink working fine (leaderboards, random opponent etc etc)
But when a player call finishMatch(), the status of match.canRematch() is always "true", beyond the result.
If the player has won the battle may not be able to ask for a rematch!
I use this code to send the result:
Games.TurnBasedMultiplayer.finishMatch(mGoogleApiClient,
mMatch.getMatchId(), mMatch.getData(), myscore, creatorscore).setResultCallback(
new ResultCallback<TurnBasedMultiplayer.UpdateMatchResult>() {
#Override
public void onResult(
TurnBasedMultiplayer.UpdateMatchResult result) {
processResult(result);
}
});
I would like to disable the possibility of revenge. How can I do?
Ok. This IS an answer.
It is not possible from the API to disallow rematch.
However, I just discovered a workaround that achieves the same effect.
detect whether a match is a rematch by calling getMatchNumber() and getPreviousMatchData(). Cancel/Dismiss the match if the former isn't 1 or the latter isn't null. It ensures a rematch user input will have the same effect as a dismissal.
when a match is completed completely (cancelled, expired, or MATCH_STATUS_COMPLETE && MATCH_TURN_STATUS_COMPLETE), dismiss it right away. It minimizes the chance that the user will even see the "Match complete, rematch" UI. This check can also be checked periodically for matches in the inbox.

How to inhibit "Loud music may harm your hearing..." warning in Android

I have an Android application for a Samsung tablet that uses an external device which draws its power from the tablet headphone jack. When the external device is powered on (by programmatically maxing out the volume), Android briefly displays a warning popup saying: "Loud music may harm your hearing if you listen to it for too long..." I would like that message to not be displayed.
Here's the offending line of code:
mAudioMgr.setStreamVolume(AudioManager.STREAM_MUSIC, mAudioMgr.getStreamMaxVolume(AudioManager.STREAM_MUSIC), 0);
It's not an option to only turn it up halfway. In fact, I've seen the tablet display the warning (when changing the volume by hand) even on volume settings lower than the max setting.
And yes, I record the original volume, and restore it when we're done with the external device.
Thanks for any suggestions.
Since you cannot disable the systems message, and you will also have a problem when the user manually lowers the volume, I suggest you do a series of controls which will help with that.
To max the volume:
public void maxVolume() {
AudioManager audioManager = (AudioManager)context.getSystemService(this.AUDIO_SERVICE);
while ( audioManager.getStreamVolume(AudioManager.STREAM_MUSIC) < audioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC)) {
audioManager.adjustStreamVolume(AudioManager.STREAM_MUSIC, AudioManager.ADJUST_RAISE, 0);
}
}
To prevent users from manually changing volume:
#Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN)
|| (keyCode == KeyEvent.KEYCODE_VOLUME_UP)
|| (keyCode == KeyEvent.KEYCODE_VOLUME_MUTE)) {
return true;
}
return super.onKeyDown(keyCode, event);
}
You can call maxVolume() in your onCreate method, and later call it just before you start using the jack output procedure to make sure the system has not changed your volume.
Alternatively you can register a listener to listen for volume changes, make maxVolume() static and call it from the listener. Hope it helps you out!
I know that this question is quite old, but I just ran across this issue myself. I figured that I would add to the answers given with what I found in case it helps someone else that happens upon this.
One of the posts here mentions that the warning is not in the AOSP, but this is not true. Please reference the VolumePanel::SafteyWarning class here: VolumePanel::SafetyWarning
Once you peruse through the SafetyWarning class you'll notice that there is a hidden method inside of the AudioManager class called disableSafeMediaVolume. You can, through reflection, invoke this hidden method easily enough, but if you do then you'll get a security exception as it requires the system permission "android.permission.STATUS_BAR_SERVICE".
So... with that said, the dialog as far as I can tell, cannot be programmatically suppressed unless you have this system permission.
What we ended up doing with the blessing of product management is we cache the volume setting in SharedPreferences and then reset it from the cache when our application starts. If it happens to be above the threshold for the warning dialog then the warning will be shown and the user will just have to press OK to get the volume setting that they want, but at least they won't have to manually reset the volume themselves.
A couple of other notes on why some don't see this dialog. You will only see it if you have headphones (or earbuds, or a wired headset) plugged into the device and you attempt to set the media volume stream over a certain threshold (on the Samsung Galaxy Tab A this threshold is 60%). If you press OK at the dialog then it will not be shown again unless you either restart the device or unplug the headphones and plug them back in (with the volume set at or above the threshold).
Hope this helps someone.
I don't know if you can consider this much of an answer but I'm pretty sure you can't remove that message as its displayed by the system automatically and not by something you can access. My Samsung Galaxy S3 does the same thing.
Also from what I can read on the net some android devices also lower the volume when you put in a jack stick so "you don't harm your hearing".
Can you override the notification by displaying your own notification just before or after perhaps? The notification is just a standard Toast.

android: turn off screen when close to face

My app allows the user to access their corporate voice mail. Normally, durring a phone call when the user holds the device up to their ear, the screen shuts off so they wont accidentally push buttons with their face. I would like to make my app do the same thing when the user is listening to their voice mail.
anyone know how to do this?
If you are allowed to look at open source code without causing yourself problems, check the source of the Android Phone Application. Specifically src/com/android/phone/PhoneApp.java and src/com/android/phone/InCallScreen.java.
From src/com/android/phone/PhoneApp.java:
//Around line 519
// Wake lock used to control proximity sensor behavior.
if ((pm.getSupportedWakeLockFlags()
& PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK) != 0x0) {
mProximityWakeLock = pm.newWakeLock(
PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK,
LOG_TAG);
}
....
// Around line 1334
if (((state == Phone.State.OFFHOOK) || mBeginningCall)&& !screenOnImmediately) {
// Phone is in use! Arrange for the screen to turn off
// automatically when the sensor detects a close object.
if (!mProximityWakeLock.isHeld()) {
if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: acquiring...");
mProximityWakeLock.acquire();
} else {
if (VDBG) Log.d(LOG_TAG, "updateProximitySensorMode: lock already held.");
}
} else {
// Phone is either idle, or ringing. We don't want any
// special proximity sensor behavior in either case.
if (mProximityWakeLock.isHeld()) {
if (DBG) Log.d(LOG_TAG, "updateProximitySensorMode: releasing...");
// Wait until user has moved the phone away from his head if we are
// releasing due to the phone call ending.
// Qtherwise, turn screen on immediately
int flags =
(screenOnImmediately ? 0 : PowerManager.WAIT_FOR_PROXIMITY_NEGATIVE);
mProximityWakeLock.release(flags);
}
}
Additionally, if you look at the code for the PowerManager class, PROXIMITY_SCREEN_OFF_WAKE_LOCK is documented (but hidden) and should do what you want ( I am not sure which API level this works for, however ) -- but not in the table for some reason.
/**
* Wake lock that turns the screen off when the proximity sensor activates.
* Since not all devices have proximity sensors, use
* {#link #getSupportedWakeLockFlags() getSupportedWakeLockFlags()} to determine if
* this wake lock mode is supported.
*
* {#hide}
*/
public static final int PROXIMITY_SCREEN_OFF_WAKE_LOCK = WAKE_BIT_PROXIMITY_SCREEN_OFF;
If you aren't afraid of using a potential undocumented feature, it should do exactly what you need.
as of API level 21 (Lollipop) you can get proximity wake lock this just like that:
if(powerManager.isWakeLockLevelSupported(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK)) {
PowerManager.WakeLock wakeLock = powerManager.newWakeLock(PowerManager.PROXIMITY_SCREEN_OFF_WAKE_LOCK, TAG);
wakeLock.setReferenceCounted(false);
return wakeLock;
} else {
return null;
}
}
then it is up to you to acquire and release the lock.
PS: PowerManager#getSupportedWakeLockFlags was hidden, but now exists nomore. They have invented isWakeLockLevelSupported instead.
Probably you don't need it anymore but for the ones that are interested in code you could have a look at my SpeakerProximity project at http://code.google.com/p/speakerproximity/
What you are seeing is the use of a proximity sensor. For devices that have one, you access it through SensorManager.

Categories

Resources