replicant-vendor_cmsdk/src/java/cyanogenmod/profiles/ConnectionSettings.java

484 lines
18 KiB
Java

/*
* Copyright (C) 2015 The CyanogenMod Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package cyanogenmod.profiles;
import android.bluetooth.BluetoothAdapter;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.location.LocationManager;
import android.net.wifi.WifiManager;
import android.net.wimax.WimaxHelper;
import android.nfc.NfcAdapter;
import android.os.Parcel;
import android.os.Parcelable;
import android.provider.Settings;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;
import com.android.internal.telephony.RILConstants;
import cyanogenmod.os.Build;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
/**
* The {@link ConnectionSettings} class allows for creating Network/Hardware overrides
* depending on their capabilities.
*
* <p>Example for enabling/disabling sync settings:
* <pre class="prettyprint">
* ConnectionSettings connectionSettings =
* new ConnectionSettings(ConnectionSettings.PROFILE_CONNECTION_SYNC,
* shouldBeEnabled() ?
* {@link BooleanState#STATE_ENABLED} : {@link BooleanState#STATE_DISALED},
* true)
* profile.setConnectionSettings(connectionSettings);
* </pre>
*/
public final class ConnectionSettings implements Parcelable {
private int mConnectionId;
private int mValue;
private boolean mOverride;
private boolean mDirty;
/**
* For use with {@link #PROFILE_CONNECTION_2G3G4G} to determine what subscription to control.
*/
private int mSubId = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
/**
* The {@link #PROFILE_CONNECTION_MOBILEDATA} allows for enabling and disabling the mobile
* data connection. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_MOBILEDATA = 0;
/**
* The {@link #PROFILE_CONNECTION_WIFI} allows for enabling and disabling the WiFi connection
* on the device. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_WIFI = 1;
/**
* The {@link #PROFILE_CONNECTION_WIFIAP} allows for enabling and disabling the WiFi hotspot
* on the device. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_WIFIAP = 2;
/**
* The {@link #PROFILE_CONNECTION_WIMAX} allows for enabling and disabling the WIMAX radio (if exists)
* on the device. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_WIMAX = 3;
/**
* The {@link #PROFILE_CONNECTION_GPS} allows for enabling and disabling the GPS radio (if exists)
* on the device. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_GPS = 4;
/**
* The {@link #PROFILE_CONNECTION_SYNC} allows for enabling and disabling the global sync state
* on the device. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_SYNC = 5;
/**
* The {@link #PROFILE_CONNECTION_BLUETOOTH} allows for enabling and disabling the Bluetooth device
* (if exists) on the device. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_BLUETOOTH = 7;
/**
* The {@link #PROFILE_CONNECTION_NFC} allows for enabling and disabling the NFC device
* (if exists) on the device. Boolean connection settings {@link BooleanState}
*/
public static final int PROFILE_CONNECTION_NFC = 8;
/**
* The {@link #PROFILE_CONNECTION_2G3G4G} allows for flipping between 2G/3G/4G (if exists)
* on the device.
*/
public static final int PROFILE_CONNECTION_2G3G4G = 9;
// retrieved from Phone.apk
private static final String ACTION_MODIFY_NETWORK_MODE =
"com.android.internal.telephony.MODIFY_NETWORK_MODE";
private static final String EXTRA_NETWORK_MODE = "networkMode";
private static final String EXTRA_SUB_ID = "subId";
/**
* BooleanStates for specific {@link ConnectionSettings}
*/
public static class BooleanState {
/** Disabled state */
public static final int STATE_DISALED = 0;
/** Enabled state */
public static final int STATE_ENABLED = 1;
}
private static final int CM_MODE_2G = 0;
private static final int CM_MODE_3G = 1;
private static final int CM_MODE_4G = 2;
private static final int CM_MODE_2G3G = 3;
private static final int CM_MODE_ALL = 4;
/** @hide */
public static final Parcelable.Creator<ConnectionSettings> CREATOR =
new Parcelable.Creator<ConnectionSettings>() {
public ConnectionSettings createFromParcel(Parcel in) {
return new ConnectionSettings(in);
}
@Override
public ConnectionSettings[] newArray(int size) {
return new ConnectionSettings[size];
}
};
/**
* Unwrap {@link ConnectionSettings} from a parcel.
* @param parcel
*/
public ConnectionSettings(Parcel parcel) {
readFromParcel(parcel);
}
/**
* Construct a {@link ConnectionSettings} with a connection id and default states.
* @param connectionId ex: #PROFILE_CONNECTION_NFC
*/
public ConnectionSettings(int connectionId) {
this(connectionId, 0, false);
}
/**
* Construct a {@link ConnectionSettings} with a connection id, default value
* {@see BooleanState}, and if the setting should override the user defaults.
* @param connectionId an identifier for the ConnectionSettings (ex:#PROFILE_CONNECTION_WIFI)
* @param value default value for the ConnectionSettings (ex:{@link BooleanState#STATE_ENABLED})
* @param override whether or not the {@link ConnectionSettings} should override user defaults
*/
public ConnectionSettings(int connectionId, int value, boolean override) {
mConnectionId = connectionId;
mValue = value;
mOverride = override;
mDirty = false;
}
/**
* Retrieve the connection id associated with the {@link ConnectionSettings}
* @return an integer identifier
*/
public int getConnectionId() {
return mConnectionId;
}
/**
* Get the default value for the {@link ConnectionSettings}
* @return integer value corresponding with its state
*/
public int getValue() {
return mValue;
}
/**
* Set the default value for the {@link ConnectionSettings}
* @param value {@link BooleanState}
*/
public void setValue(int value) {
mValue = value;
mDirty = true;
}
/**
* Set whether or not the {@link ConnectionSettings} should override default user values
* @param override boolean override
*/
public void setOverride(boolean override) {
mOverride = override;
mDirty = true;
}
public void setSubId(int subId) {
mSubId = subId;
mDirty = true;
}
/**
* Check whether or not the {@link ConnectionSettings} overrides user settings.
* @return true if override
*/
public boolean isOverride() {
return mOverride;
}
/**
* Get the subscription id which this {@link ConnectionSettings} should apply to.
* @return
*/
public int getSubId() {
return mSubId;
}
/** @hide */
public boolean isDirty() {
return mDirty;
}
/** @hide */
public void processOverride(Context context) {
BluetoothAdapter bta = BluetoothAdapter.getDefaultAdapter();
LocationManager lm = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
WifiManager wm = (WifiManager) context.getSystemService(Context.WIFI_SERVICE);
TelephonyManager tm = (TelephonyManager)
context.getSystemService(Context.TELEPHONY_SERVICE);
NfcAdapter nfcAdapter = null;
try {
nfcAdapter = NfcAdapter.getNfcAdapter(context);
} catch (UnsupportedOperationException e) {
//Nfc not available
}
boolean forcedState = getValue() == 1;
boolean currentState;
switch (getConnectionId()) {
case PROFILE_CONNECTION_MOBILEDATA:
currentState = tm.getDataEnabled();
if (forcedState != currentState) {
int phoneCount = tm.getPhoneCount();
for (int i = 0; i < phoneCount; i++) {
Settings.Global.putInt(context.getContentResolver(),
Settings.Global.MOBILE_DATA + i, (forcedState) ? 1 : 0);
int[] subId = SubscriptionManager.getSubId(i);
tm.setDataEnabled(subId[0], forcedState);
}
}
break;
case PROFILE_CONNECTION_2G3G4G:
if (Build.CM_VERSION.SDK_INT >= Build.CM_VERSION_CODES.ELDERBERRY) {
Intent intent = new Intent(ACTION_MODIFY_NETWORK_MODE);
intent.putExtra(EXTRA_NETWORK_MODE, getValue());
intent.putExtra(EXTRA_SUB_ID, getSubId());
context.sendBroadcast(intent, "com.android.phone.CHANGE_NETWORK_MODE");
} else {
Intent intent = new Intent(ACTION_MODIFY_NETWORK_MODE);
switch(getValue()) {
case CM_MODE_2G:
intent.putExtra(EXTRA_NETWORK_MODE, RILConstants.NETWORK_MODE_GSM_ONLY);
break;
case CM_MODE_3G:
intent.putExtra(EXTRA_NETWORK_MODE, RILConstants.NETWORK_MODE_WCDMA_ONLY);
break;
case CM_MODE_4G:
intent.putExtra(EXTRA_NETWORK_MODE, RILConstants.NETWORK_MODE_LTE_ONLY);
break;
case CM_MODE_2G3G:
intent.putExtra(EXTRA_NETWORK_MODE, RILConstants.NETWORK_MODE_WCDMA_PREF);
break;
case CM_MODE_ALL:
intent.putExtra(EXTRA_NETWORK_MODE,
RILConstants.NETWORK_MODE_LTE_GSM_WCDMA);
break;
default:
return;
}
context.sendBroadcast(intent);
}
break;
case PROFILE_CONNECTION_BLUETOOTH:
int btstate = bta.getState();
if (forcedState && (btstate == BluetoothAdapter.STATE_OFF
|| btstate == BluetoothAdapter.STATE_TURNING_OFF)) {
bta.enable();
} else if (!forcedState && (btstate == BluetoothAdapter.STATE_ON
|| btstate == BluetoothAdapter.STATE_TURNING_ON)) {
bta.disable();
}
break;
case PROFILE_CONNECTION_GPS:
currentState = lm.isProviderEnabled(LocationManager.GPS_PROVIDER);
if (currentState != forcedState) {
Settings.Secure.setLocationProviderEnabled(context.getContentResolver(),
LocationManager.GPS_PROVIDER, forcedState);
}
break;
case PROFILE_CONNECTION_SYNC:
currentState = ContentResolver.getMasterSyncAutomatically();
if (forcedState != currentState) {
ContentResolver.setMasterSyncAutomatically(forcedState);
}
break;
case PROFILE_CONNECTION_WIFI:
int wifiApState = wm.getWifiApState();
currentState = wm.isWifiEnabled();
if (currentState != forcedState) {
// Disable wifi tether
if (forcedState && (wifiApState == WifiManager.WIFI_AP_STATE_ENABLING) ||
(wifiApState == WifiManager.WIFI_AP_STATE_ENABLED)) {
wm.setWifiApEnabled(null, false);
}
wm.setWifiEnabled(forcedState);
}
break;
case PROFILE_CONNECTION_WIFIAP:
int wifiState = wm.getWifiState();
currentState = wm.isWifiApEnabled();
if (currentState != forcedState) {
// Disable wifi
if (forcedState && (wifiState == WifiManager.WIFI_STATE_ENABLING) ||
(wifiState == WifiManager.WIFI_STATE_ENABLED)) {
wm.setWifiEnabled(false);
}
wm.setWifiApEnabled(null, forcedState);
}
break;
case PROFILE_CONNECTION_WIMAX:
if (WimaxHelper.isWimaxSupported(context)) {
currentState = WimaxHelper.isWimaxEnabled(context);
if (currentState != forcedState) {
WimaxHelper.setWimaxEnabled(context, forcedState);
}
}
break;
case PROFILE_CONNECTION_NFC:
if (nfcAdapter != null) {
int adapterState = nfcAdapter.getAdapterState();
currentState = (adapterState == NfcAdapter.STATE_ON ||
adapterState == NfcAdapter.STATE_TURNING_ON);
if (currentState != forcedState) {
if (forcedState) {
nfcAdapter.enable();
} else if (!forcedState && adapterState != NfcAdapter.STATE_TURNING_OFF) {
nfcAdapter.disable();
}
}
}
break;
}
}
/** @hide */
public static ConnectionSettings fromXml(XmlPullParser xpp, Context context)
throws XmlPullParserException, IOException {
int event = xpp.next();
ConnectionSettings connectionDescriptor = new ConnectionSettings(0);
while (event != XmlPullParser.END_TAG || !xpp.getName().equals("connectionDescriptor")) {
if (event == XmlPullParser.START_TAG) {
String name = xpp.getName();
if (name.equals("connectionId")) {
connectionDescriptor.mConnectionId = Integer.parseInt(xpp.nextText());
} else if (name.equals("value")) {
connectionDescriptor.mValue = Integer.parseInt(xpp.nextText());
} else if (name.equals("override")) {
connectionDescriptor.mOverride = Boolean.parseBoolean(xpp.nextText());
} else if (name.equals("subId")) {
connectionDescriptor.mSubId = Integer.parseInt(xpp.nextText());
}
} else if (event == XmlPullParser.END_DOCUMENT) {
throw new IOException("Premature end of file while parsing connection settings");
}
event = xpp.next();
}
return connectionDescriptor;
}
/** @hide */
public void getXmlString(StringBuilder builder, Context context) {
builder.append("<connectionDescriptor>\n<connectionId>");
builder.append(mConnectionId);
builder.append("</connectionId>\n<value>");
builder.append(mValue);
builder.append("</value>\n<override>");
builder.append(mOverride);
builder.append("</override>\n");
if (Build.CM_VERSION.SDK_INT >= Build.CM_VERSION_CODES.ELDERBERRY) {
if (mConnectionId == PROFILE_CONNECTION_2G3G4G
&& mSubId != SubscriptionManager.INVALID_SUBSCRIPTION_ID) {
builder.append("<subId>").append(mSubId).append("</subId>\n");
}
}
builder.append("</connectionDescriptor>\n");
}
@Override
public int describeContents() {
return 0;
}
/** @hide */
@Override
public void writeToParcel(Parcel dest, int flags) {
// Write parcelable version, make sure to define explicit changes
// within {@link Build.PARCELABLE_VERSION);
dest.writeInt(Build.PARCELABLE_VERSION);
// Inject a placeholder that will store the parcel size from this point on
// (not including the size itself).
int sizePosition = dest.dataPosition();
dest.writeInt(0);
int startPosition = dest.dataPosition();
// === BOYSENBERRY ===
dest.writeInt(mConnectionId);
dest.writeInt(mOverride ? 1 : 0);
dest.writeInt(mValue);
dest.writeInt(mDirty ? 1 : 0);
// === ELDERBERRY ===
if (mConnectionId == PROFILE_CONNECTION_2G3G4G) {
dest.writeInt(mSubId);
}
// Go back and write size
int parcelableSize = dest.dataPosition() - startPosition;
dest.setDataPosition(sizePosition);
dest.writeInt(parcelableSize);
dest.setDataPosition(startPosition + parcelableSize);
}
/** @hide */
public void readFromParcel(Parcel in) {
// Read parcelable version, make sure to define explicit changes
// within {@link Build.PARCELABLE_VERSION);
int parcelableVersion = in.readInt();
int parcelableSize = in.readInt();
int startPosition = in.dataPosition();
// Pattern here is that all new members should be added to the end of
// the writeToParcel method. Then we step through each version, until the latest
// API release to help unravel this parcel
if (parcelableVersion >= Build.CM_VERSION_CODES.BOYSENBERRY) {
mConnectionId = in.readInt();
mOverride = in.readInt() != 0;
mValue = in.readInt();
mDirty = in.readInt() != 0;
}
if (parcelableVersion >= Build.CM_VERSION_CODES.ELDERBERRY) {
if (mConnectionId == PROFILE_CONNECTION_2G3G4G) {
mSubId = in.readInt();
}
}
in.setDataPosition(startPosition + parcelableSize);
}
}