Setting airplane mode does not completely work - android

I've written the code below to set the phone into airplane mode to save power. The devices is being used as a WiFi-Hotspot to relay data from some sensors in a village in Indonesia. The sensors send their data at the same time so I just need to come out of airplane mode for five minutes at midnight and then reenter airplane mode.
The problem is the cellular radio is not shut off and the airplane icon does not appear. Though the the phone reports its status as airplane_mode on, it is still possible to call it. Other widgets in the marketplace seem to fare no better. I've tried "Airplane Mode Wi-Fi Tool". It too can not get the airplane icon to appear nor disable cell radio. When watching LogCat while using the device settings to go to Airplane mode, I can see that much more is happening than when trying from the program.
If I load my program on a Droid, this code works as expected. AIRPLANE_MODE_RADIOS is set to cell, bluetooth, wifi.
The offending device is a Samsung Galaxy 5, I5500 tested with:
-Froyo 2.2 build FROYO.UYJP2
-Froyo 2.2.1 build FROYO.UYJPE
One interesting side note: if I programmatically set airplane mode and then power cycle the device, it comes up in full airplane mode, rejects incoming calls etc.
Do others have similar stories with this or other devices? Is there a way to specifically turn off cell only?
public static void setAirplaneMode(Context context, boolean status) {
boolean isAM = Settings.System.getInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0) != 0;
String radios = Settings.System.getString(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_RADIOS);
//This line is reporting all radios affected but annunciator does not seem to think so. Does not show airplane
Wake.logger("Airplane mode is: " + isAM + " changing to " + status + " For radios: " + radios, false);
// It appears Airplane mode should only be toggled. Don't reset to
// current state.
if (isAM && !status) {
Settings.System.putInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 0);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", 0);
context.sendBroadcast(intent);
return;
}
if (!isAM && status) {
Settings.System.putInt(context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, 1);
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", 1);
context.sendBroadcast(intent);
return;
}
}

Classic bit twister error. The extra data argument in the broadcast intent needed to be true/false, not 1/0. Ugh!!!
intent.putExtra("state", true); //Not 1!!
One phone worked another didn't. Now both do.

Related

Why doesn't toggling Airplane Mode also toggle Wifi/Cellular state (Oreo)?

After reading through a bunch of stale guides and stackoverflows, I was able to usb adb to install an apk as a system app in /system/priv-app that successfully toggles AirplaneMode in Android oreo:
// method in Activity, called via click listener on a Button
private void setMobileRadioEnabled_Option1(boolean enabled) {
android.content.Context context = this;
int value = enabled ? 0 : 1;
if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
Settings.System.putInt(
context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, value);
} else {
Settings.Global.putInt(
context.getContentResolver(),
Settings.Global.AIRPLANE_MODE_ON, value);
}
}
Permissions in AndroidManifest.xml:
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
Standard release build in AndroidStudio with custom signing keys, installed via:
adb root
adb remount
adb push app-release.apk /system/priv-app
adb shell chmod 644 /system/priv-app/app-release.apk
adb reboot
On reboot, the app is installed and I can run it without issue.
I check in the notifications drawer / status bar what things are like to start with:
I then click my Button in the app, and check what happens:
As you can see, airplane mode seems to be successfully enabled based on the status of the airplane mode icon. But wifi and cellular data continue to be connected, and the status bar doesn't replace the text "Android" with "Airplane mode". In this state, if I hop over to chrome, I can clearly load websites I've never visited before. So airplane mode doesn't in fact seem to be actually on.
What am I doing wrong? I expect turning on airplane mode via System.putInt() to have the same effect as tapping the airplane mode tile in the status bar. No exceptions or useful error information spitting to logcat when I execute the code.
Checking this answer it seems that you need to send a broadcast to notify that you changed the airplane mode.
The broadcast should be:
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", < current value of the airplane mode >);
sendBroadcast(intent);
Alternatively to jonathanrz's additional code above, which I believe is closer to canonical, I found that the following worked in place of the Settings.System.putInt() code and did not require sending the intent (or adding the permission(s) necessary to send it), at least on Oreo. I created it by merging a few answers and offhand comments from other posts, particularly an answer sketch hidden in a comment by "Navas pk" on Toggle airplane mode in Android:
private void setMobileRadioEnabled_Option2(boolean enabled) {
try {
final ConnectivityManager mConnectivityManager = (ConnectivityManager) getSystemService(android.content.Context.CONNECTIVITY_SERVICE);
final Class mClass = Class.forName(mConnectivityManager.getClass().getName());
final Method setAirplaneMode = mClass.getDeclaredMethod("setAirplaneMode", Boolean.TYPE);
setAirplaneMode.setAccessible(true);
setAirplaneMode.invoke(mConnectivityManager, !enabled);
} catch (Exception e) {
e.printStackTrace();
}
}

Detect changes in power status of a TV connected to an Android device via HDMI

I'm building an Android media player application that I intend to use to play media (videos, pictures, etc.) on a TV while connected via an HDMI cable.
I want to have the media player app pause when the TV's power status is OFF and want it to play when the TV is turned ON.
How do I detect the TV's power status within my Android application when my Android device is connected to the TV via HDMI?
Both the TV and the Android device have support for HDMI-CEC. The device in question is an ODROID C2. I've seen this functionality on the KODI Android application which has a feature to pause the video when the HDMI-CEC status is OFF, I'm looking to implement this within my app as well.
Any help is appreciated. Thanks in advance!
EDIT: Progress below
I tried reading the status of the HDMI connection from within this file /sys/devices/virtual/switch/hdmi/state. However, this file holds int 1 no matter whether the power status of the connected screen / TV is ON or OFF.
2nd Progress update
I'm still working on this. Will not give up, and once I'm done I will surely post the answer here.
You can listen for changes in HDMI status (0 for unplugged and 1 for plugged) by registering for ACTION_HDMI_AUDIO_PLUG. It reports with status 0 when tv is switched off, switches to any other display medium or HDMI is removed. To read into its technicality, you can check out how hot plug detection works in HDMI. Overall, your app can at all times monitor whether the display can currently play your content or not. I have myself implemented this in a solution (on X96 mini android box & amazon fire-stick) where I needed to ensure that the content was actually being played because it included paid content. Also, I have attached the sample code file.
Note: This solution will only work when android device is HDMI source not sink!
Here's the documentation link too- https://developer.android.com/reference/android/media/AudioManager#ACTION_HDMI_AUDIO_PLUG
private BroadcastReceiver eventReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
// pause video
String action = intent.getAction();
switch (action) {
case ACTION_HDMI_AUDIO_PLUG :
// EXTRA_AUDIO_PLUG_STATE: 0 - UNPLUG, 1 - PLUG
Toast.makeText(getApplicationContext(),"HDMI PLUGGED OR UNPLUGGED",Toast.LENGTH_LONG).show();
Log.d("MainActivity", "ACTION_HDMI_AUDIO_PLUG " + intent.getIntExtra(EXTRA_AUDIO_PLUG_STATE, -1));
((TextView)(findViewById(R.id.textView))).setText(((TextView)(findViewById(R.id.textView))).getText().toString().concat("At "+System.nanoTime()+": "+intent.getIntExtra(EXTRA_AUDIO_PLUG_STATE, -1) +"\n"));
break;
}
}
};
#Override
protected void onPause() {
super.onPause();
unregisterReceiver(eventReceiver);
}
#Override
protected void onResume() {
super.onResume();
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_HDMI_AUDIO_PLUG);
registerReceiver(eventReceiver, filter);
}
In Some TV's, You need to monitor that (sys/class/amhdmitx/amhdmitx0/hpd_state) folder for changes by 500 ms Interval. because it'll change from 1 to 0 and again from 0 to 1 within 1 seconds.

Android: How to Toggle Between Vibrate Settings (Always, Never, Only in Silent Mode, Only When Not in Silent Mode)? Revisited

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() ??? )

How to disable GSM connection in Android programmatically

I want to enable/disable an Android phone's GSM connection. I need to disable/enable calls and SMS as required. How might I do this?
EDIT: This solution will also turn off wifi, bluetooth, etc...
If you want to turn off radio only, I think it's related to this issue: http://code.google.com/p/android/issues/detail?id=1065
I am really pessimistic about finding a good solution, but curious to see other answers.
See the blog article Android: Controlling Airplane Mode ,
// Toggle airplane mode.
Settings.System.putInt(
context.getContentResolver(),
Settings.System.AIRPLANE_MODE_ON, isEnabled ? 0 : 1);
// Post an intent to reload.
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", !isEnabled);
sendBroadcast(intent);
where isEnabled is whether airplane mode is enabled or not.
Don't forget you need the WRITE_SETTINGS permission to do this, though.
/* Toggle airplane mode for 1 of the 4 allowed types
* type allowed values: cell, wifi, bluetooth, nfc
*/
private void changeRadioComponentEnabled(Context context, String type, boolean radio_component_enabled, boolean reset){
// now toggle airplane mode from on to off, or vice versa
Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, radio_component_enabled ? 0 : 1);
// now change system behavior so that only one component is turned off
// this also affects the future behavior of the system button for toggling air-plane mode.
// to reset it in order to maintain the system behavior, set reset to true, otherwise we lazily make sure mobile voice is always on
Settings.System.putString(context.getContentResolver(), Settings.System.AIRPLANE_MODE_RADIOS, type);
// post an intent to reload so the menu button switches to the new state we set
Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED);
intent.putExtra("state", radio_component_enabled ? false : true);
context.sendBroadcast(intent);
// revert to default system behavior or not
if (reset){ Settings.System.putString(context.getContentResolver(), Settings.System.AIRPLANE_MODE_RADIOS, "cell,bluetooth,wifi,nfc"); }
// if reset to default is not chosen, always enable mobile cell at least
// but only if NOT changing the mobile connection...
else if (type.indexOf("cell") == 0) { Settings.System.putString(context.getContentResolver(), Settings.System.AIRPLANE_MODE_RADIOS, "cell");}
}//end method
naturally this require the permission android.permission.WRITE_SETTINGS, and for bluetooth android.permission.BLUETOOTH_ADMIN. For NFC you might need android.permission.NFC.
EDITS: heavily modified since original, since I was actually using this in a different way in my own app

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