diff options
Diffstat (limited to 'sdk/src/java/cyanogenmod/profiles/ConnectionSettings.java')
-rw-r--r-- | sdk/src/java/cyanogenmod/profiles/ConnectionSettings.java | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/sdk/src/java/cyanogenmod/profiles/ConnectionSettings.java b/sdk/src/java/cyanogenmod/profiles/ConnectionSettings.java new file mode 100644 index 0000000..19954dd --- /dev/null +++ b/sdk/src/java/cyanogenmod/profiles/ConnectionSettings.java @@ -0,0 +1,475 @@ +/* + * 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 cyanogenmod.os.Concierge; +import cyanogenmod.os.Concierge.ParcelInfo; + +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) { + // Tell the concierge to prepare the parcel + ParcelInfo parcelInfo = Concierge.prepareParcel(dest); + + // === 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); + } + + // Complete the parcel info for the concierge + parcelInfo.complete(); + } + + /** @hide */ + public void readFromParcel(Parcel in) { + // Read parcelable version via the Concierge + ParcelInfo parcelInfo = Concierge.receiveParcel(in); + int parcelableVersion = parcelInfo.getParcelVersion(); + + // 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(); + } + } + + // Complete parcel info for the concierge + parcelInfo.complete(); + } +} |