aboutsummaryrefslogtreecommitdiffstats
path: root/sdk/src/java/cyanogenmod/app/Profile.java
diff options
context:
space:
mode:
Diffstat (limited to 'sdk/src/java/cyanogenmod/app/Profile.java')
-rwxr-xr-xsdk/src/java/cyanogenmod/app/Profile.java1365
1 files changed, 1365 insertions, 0 deletions
diff --git a/sdk/src/java/cyanogenmod/app/Profile.java b/sdk/src/java/cyanogenmod/app/Profile.java
new file mode 100755
index 0000000..9a4666d
--- /dev/null
+++ b/sdk/src/java/cyanogenmod/app/Profile.java
@@ -0,0 +1,1365 @@
+/*
+ * 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.app;
+
+import android.content.Context;
+import android.media.AudioManager;
+import android.os.Parcel;
+import android.os.ParcelUuid;
+import android.os.Parcelable;
+import android.os.UserHandle;
+import android.provider.Settings;
+import android.text.TextUtils;
+import android.util.Log;
+
+import com.android.internal.policy.IKeyguardService;
+import cyanogenmod.os.Build;
+import cyanogenmod.profiles.AirplaneModeSettings;
+import cyanogenmod.profiles.BrightnessSettings;
+import cyanogenmod.profiles.ConnectionSettings;
+import cyanogenmod.profiles.LockSettings;
+import cyanogenmod.profiles.RingModeSettings;
+import cyanogenmod.profiles.StreamSettings;
+
+import cyanogenmod.os.Concierge;
+import cyanogenmod.os.Concierge.ParcelInfo;
+
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.UUID;
+
+/**
+ * A class that represents a device profile.
+ *
+ * A {@link Profile} can serve a multitude of purposes, allowing the creator(user)
+ * to set overrides for streams, triggers, screen lock, brightness, various other
+ * settings.
+ */
+public final class Profile implements Parcelable, Comparable {
+
+ private String mName;
+
+ private int mNameResId;
+
+ private UUID mUuid;
+
+ private ArrayList<UUID> mSecondaryUuids = new ArrayList<UUID>();
+
+ private Map<UUID, ProfileGroup> profileGroups = new HashMap<UUID, ProfileGroup>();
+
+ private ProfileGroup mDefaultGroup;
+
+ private boolean mStatusBarIndicator = false;
+
+ private boolean mDirty;
+
+ private static final String TAG = "Profile";
+
+ private int mProfileType;
+
+ private Map<Integer, StreamSettings> streams = new HashMap<Integer, StreamSettings>();
+
+ private Map<String, ProfileTrigger> mTriggers = new HashMap<String, ProfileTrigger>();
+
+ private Map<Integer, ConnectionSettings> connections = new HashMap<Integer, ConnectionSettings>();
+
+ private Map<Integer, ConnectionSettings> networkConnectionSubIds = new HashMap<>();
+
+ private RingModeSettings mRingMode = new RingModeSettings();
+
+ private AirplaneModeSettings mAirplaneMode = new AirplaneModeSettings();
+
+ private BrightnessSettings mBrightness = new BrightnessSettings();
+
+ private LockSettings mScreenLockMode = new LockSettings();
+
+ private int mExpandedDesktopMode = ExpandedDesktopMode.DEFAULT;
+
+ private int mDozeMode = DozeMode.DEFAULT;
+
+ private int mNotificationLightMode = NotificationLightMode.DEFAULT;
+
+ /**
+ * Lock modes of a device
+ */
+ public static class LockMode {
+ /** Represents a default state lock mode (user choice) */
+ public static final int DEFAULT = 0;
+ /** Represents an insecure state lock mode, where the device has no security screen */
+ public static final int INSECURE = 1;
+ /** Represents a disabled state lock mode, where the devices lock screen can be removed */
+ public static final int DISABLE = 2;
+ }
+
+ /**
+ * Expanded desktop modes available on a device
+ */
+ public static class ExpandedDesktopMode {
+ /** Represents a default state expanded desktop mode (user choice) */
+ public static final int DEFAULT = 0;
+ /** Represents an enabled expanded desktop mode */
+ public static final int ENABLE = 1;
+ /** Represents a disabled expanded desktop mode */
+ public static final int DISABLE = 2;
+ }
+
+ /**
+ * Doze modes available on a device
+ */
+ public static class DozeMode {
+ /** Represents a default Doze mode (user choice) */
+ public static final int DEFAULT = 0;
+ /** Represents an enabled Doze mode */
+ public static final int ENABLE = 1;
+ /** Represents an disabled Doze mode */
+ public static final int DISABLE = 2;
+ }
+
+ /**
+ * Notification light modes available on a device
+ */
+ public static class NotificationLightMode {
+ /** Represents a default Notification light mode (user choice) */
+ public static final int DEFAULT = 0;
+ /** Represents an enabled Notification light mode */
+ public static final int ENABLE = 1;
+ /** Represents a disabled Notification light mode */
+ public static final int DISABLE = 2;
+ }
+
+ /**
+ * Available trigger types on the device, usually hardware
+ */
+ public static class TriggerType {
+ /** Represents a WiFi trigger type */
+ public static final int WIFI = 0;
+ /** Represents a Bluetooth trigger type */
+ public static final int BLUETOOTH = 1;
+ }
+
+ /**
+ * Various trigger states associated with a {@link TriggerType}
+ */
+ public static class TriggerState {
+ /** A {@link TriggerState) for when the {@link TriggerType} connects */
+ public static final int ON_CONNECT = 0;
+ /** A {@link TriggerState) for when the {@link TriggerType} disconnects */
+ public static final int ON_DISCONNECT = 1;
+ /** A {@link TriggerState) for when the {@link TriggerType} is disabled */
+ public static final int DISABLED = 2;
+ /**
+ * A {@link TriggerState) for when the {@link TriggerType#BLUETOOTH}
+ * connects for A2DP session
+ */
+ public static final int ON_A2DP_CONNECT = 3;
+ /**
+ * A {@link TriggerState) for when the {@link TriggerType#BLUETOOTH}
+ * disconnects from A2DP session
+ */
+ public static final int ON_A2DP_DISCONNECT = 4;
+ }
+
+ /**
+ * A {@link Profile} type
+ */
+ public static class Type {
+ /** Profile type which represents a toggle {@link Profile} */
+ public static final int TOGGLE = 0;
+ /** Profile type which represents a conditional {@link Profile} */
+ public static final int CONDITIONAL = 1;
+ }
+
+ /**
+ * A {@link ProfileTrigger} is a {@link TriggerType} which can be queried from the OS
+ */
+ public static class ProfileTrigger implements Parcelable {
+ private int mType;
+ private String mId;
+ private String mName;
+ private int mState;
+
+
+ /**
+ * Construct a {@link ProfileTrigger} based on its type {@link Profile.TriggerType} and if
+ * the trigger should fire on a {@link Profile.TriggerState} change.
+ *
+ * Example:
+ * <pre class="prettyprint">
+ * triggerId = trigger.getSSID(); // Use the AP's SSID as identifier
+ * triggerName = trigger.getTitle(); // Use the AP's name as the trigger name
+ * triggerType = Profile.TriggerType.WIFI; // This is a wifi trigger
+ * triggerState = Profile.TriggerState.ON_CONNECT; // On Connect of this, trigger
+ *
+ * Profile.ProfileTrigger profileTrigger =
+ * new Profile.ProfileTrigger(triggerType, triggerId, triggerState, triggerName);
+ * </pre>
+ *
+ * @param type a {@link Profile.TriggerType}
+ * @param id an identifier for the ProfileTrigger
+ * @param state {@link Profile.TriggerState} depending on the TriggerType
+ * @param name an identifying name for the ProfileTrigger
+ */
+ public ProfileTrigger(int type, String id, int state, String name) {
+ mType = type;
+ mId = id;
+ mState = state;
+ mName = name;
+ }
+
+ private ProfileTrigger(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) {
+ mType = in.readInt();
+ mId = in.readString();
+ mState = in.readInt();
+ mName = in.readString();
+ }
+
+ // Complete parcel info for the concierge
+ parcelInfo.complete();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ // Tell the concierge to prepare the parcel
+ ParcelInfo parcelInfo = Concierge.prepareParcel(dest);
+
+ dest.writeInt(mType);
+ dest.writeString(mId);
+ dest.writeInt(mState);
+ dest.writeString(mName);
+
+ // Complete the parcel info for the concierge
+ parcelInfo.complete();
+ }
+
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Get the {@link ProfileTrigger} {@link TriggerType}
+ * @return {@link TriggerType}
+ */
+ public int getType() {
+ return mType;
+ }
+
+ /**
+ * Get the name associated with the {@link ProfileTrigger}
+ * @return a string name
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Get the id associated with the {@link ProfileTrigger}
+ * @return an string identifier
+ */
+ public String getId() {
+ return mId;
+ }
+
+ /**
+ * Get the state associated with the {@link ProfileTrigger}
+ * @return an integer indicating the state
+ */
+ public int getState() {
+ return mState;
+ }
+
+ /**
+ * @hide
+ */
+ public void getXmlString(StringBuilder builder, Context context) {
+ final String itemType = mType == TriggerType.WIFI ? "wifiAP" : "btDevice";
+
+ builder.append("<");
+ builder.append(itemType);
+ builder.append(" ");
+ builder.append(getIdType(mType));
+ builder.append("=\"");
+ builder.append(mId);
+ builder.append("\" state=\"");
+ builder.append(mState);
+ builder.append("\" name=\"");
+ builder.append(mName);
+ builder.append("\"></");
+ builder.append(itemType);
+ builder.append(">\n");
+ }
+
+ /**
+ * @hide
+ */
+ public static ProfileTrigger fromXml(XmlPullParser xpp, Context context) {
+ final String name = xpp.getName();
+ final int type;
+
+ if (name.equals("wifiAP")) {
+ type = TriggerType.WIFI;
+ } else if (name.equals("btDevice")) {
+ type = TriggerType.BLUETOOTH;
+ } else {
+ return null;
+ }
+
+ String id = xpp.getAttributeValue(null, getIdType(type));
+ int state = Integer.valueOf(xpp.getAttributeValue(null, "state"));
+ String triggerName = xpp.getAttributeValue(null, "name");
+ if (triggerName == null) {
+ triggerName = id;
+ }
+
+ return new ProfileTrigger(type, id, state, triggerName);
+ }
+
+ private static String getIdType(int type) {
+ return type == TriggerType.WIFI ? "ssid" : "address";
+ }
+
+ /**
+ * @hide
+ */
+ public static final Parcelable.Creator<ProfileTrigger> CREATOR
+ = new Parcelable.Creator<ProfileTrigger>() {
+ public ProfileTrigger createFromParcel(Parcel in) {
+ return new ProfileTrigger(in);
+ }
+
+ @Override
+ public ProfileTrigger[] newArray(int size) {
+ return new ProfileTrigger[size];
+ }
+ };
+ }
+
+ /** @hide */
+ public static final Parcelable.Creator<Profile> CREATOR = new Parcelable.Creator<Profile>() {
+ public Profile createFromParcel(Parcel in) {
+ return new Profile(in);
+ }
+
+ @Override
+ public Profile[] newArray(int size) {
+ return new Profile[size];
+ }
+ };
+
+ public Profile(String name) {
+ this(name, -1, UUID.randomUUID());
+ }
+
+ /** @hide */
+ public Profile(String name, int nameResId, UUID uuid) {
+ mName = name;
+ mNameResId = nameResId;
+ mUuid = uuid;
+ mProfileType = Type.TOGGLE; //Default to toggle type
+ mDirty = false;
+ }
+
+ private Profile(Parcel in) {
+ readFromParcel(in);
+ }
+
+ /**
+ * Get the {@link TriggerState} for a {@link ProfileTrigger} with a given id
+ * @param type {@link TriggerType}
+ * @param id string id of {@link ProfileTrigger}
+ * @return {@link TriggerState}
+ */
+ public int getTriggerState(int type, String id) {
+ ProfileTrigger trigger = id != null ? mTriggers.get(id) : null;
+ if (trigger != null) {
+ return trigger.mState;
+ }
+ return TriggerState.DISABLED;
+ }
+
+ /**
+ * Get all the {@link ProfileTrigger}s for a given {@link TriggerType}
+ * @param type {@link TriggerType}
+ * @return an array list of {@link ProfileTrigger}s
+ */
+ public ArrayList<ProfileTrigger> getTriggersFromType(int type) {
+ ArrayList<ProfileTrigger> result = new ArrayList<ProfileTrigger>();
+ for (Entry<String, ProfileTrigger> profileTrigger: mTriggers.entrySet()) {
+ ProfileTrigger trigger = profileTrigger.getValue();
+ if (trigger.getType() == type) {
+ result.add(trigger);
+ }
+ }
+ return result;
+ }
+
+ /**
+ * Set a custom {@link ProfileTrigger}
+ * @hide
+ */
+ public void setTrigger(int type, String id, int state, String name) {
+ if (id == null
+ || type < TriggerType.WIFI || type > TriggerType.BLUETOOTH
+ || state < TriggerState.ON_CONNECT || state > TriggerState.ON_A2DP_DISCONNECT) {
+ return;
+ }
+
+ ProfileTrigger trigger = mTriggers.get(id);
+
+ if (state == TriggerState.DISABLED) {
+ if (trigger != null) {
+ mTriggers.remove(id);
+ }
+ } else if (trigger != null) {
+ trigger.mState = state;
+ } else {
+ mTriggers.put(id, new ProfileTrigger(type, id, state, name));
+ }
+
+ mDirty = true;
+ }
+
+ /**
+ * Set a {@link ProfileTrigger} on the {@link Profile}
+ * @param trigger a {@link ProfileTrigger}
+ */
+ public void setTrigger(ProfileTrigger trigger) {
+ setTrigger(trigger.getType(), trigger.getId(), trigger.getState(), trigger.getName());
+ }
+
+ public int compareTo(Object obj) {
+ Profile tmp = (Profile) obj;
+ if (mName.compareTo(tmp.mName) < 0) {
+ return -1;
+ } else if (mName.compareTo(tmp.mName) > 0) {
+ return 1;
+ }
+ return 0;
+ }
+
+ /**
+ * Add a {@link ProfileGroup} to the {@link Profile}
+ * @param profileGroup
+ * @hide
+ */
+ public void addProfileGroup(ProfileGroup profileGroup) {
+ if (profileGroup == null) {
+ return;
+ }
+
+ if (profileGroup.isDefaultGroup()) {
+ /* we must not have more than one default group */
+ if (mDefaultGroup != null) {
+ return;
+ }
+ mDefaultGroup = profileGroup;
+ }
+ profileGroups.put(profileGroup.getUuid(), profileGroup);
+ mDirty = true;
+ }
+
+ /**
+ * Remove a {@link ProfileGroup} with a given {@link UUID}
+ * @param uuid
+ * @hide
+ */
+ public void removeProfileGroup(UUID uuid) {
+ if (!profileGroups.get(uuid).isDefaultGroup()) {
+ profileGroups.remove(uuid);
+ } else {
+ Log.e(TAG, "Cannot remove default group: " + uuid);
+ }
+ }
+
+ /**
+ * Get {@link ProfileGroup}s associated with the {@link Profile}
+ * @return {@link ProfileGroup[]}
+ * @hide
+ */
+ public ProfileGroup[] getProfileGroups() {
+ return profileGroups.values().toArray(new ProfileGroup[profileGroups.size()]);
+ }
+
+ /**
+ * Get a {@link ProfileGroup} with a given {@link UUID}
+ * @param uuid
+ * @return a {@link ProfileGroup}
+ * @hide
+ */
+ public ProfileGroup getProfileGroup(UUID uuid) {
+ return profileGroups.get(uuid);
+ }
+
+ /**
+ * Get the default {@link ProfileGroup} associated with the {@link Profile}
+ * @return the default {@link ProfileGroup}
+ * @hide
+ */
+ public ProfileGroup getDefaultGroup() {
+ return mDefaultGroup;
+ }
+
+ /** @hide */
+ @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 ===
+ if (!TextUtils.isEmpty(mName)) {
+ dest.writeInt(1);
+ dest.writeString(mName);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mNameResId != 0) {
+ dest.writeInt(1);
+ dest.writeInt(mNameResId);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mUuid != null) {
+ dest.writeInt(1);
+ new ParcelUuid(mUuid).writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mSecondaryUuids != null && !mSecondaryUuids.isEmpty()) {
+ ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>(mSecondaryUuids.size());
+ for (UUID u : mSecondaryUuids) {
+ uuids.add(new ParcelUuid(u));
+ }
+ dest.writeInt(1);
+ dest.writeParcelableArray(uuids.toArray(new Parcelable[uuids.size()]), flags);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeInt(mStatusBarIndicator ? 1 : 0);
+ dest.writeInt(mProfileType);
+ dest.writeInt(mDirty ? 1 : 0);
+ if (profileGroups != null && !profileGroups.isEmpty()) {
+ dest.writeInt(1);
+ dest.writeTypedArray(profileGroups.values().toArray(
+ new ProfileGroup[0]), flags);
+ } else {
+ dest.writeInt(0);
+ }
+ if (streams != null && !streams.isEmpty()) {
+ dest.writeInt(1);
+ dest.writeTypedArray(streams.values().toArray(
+ new StreamSettings[0]), flags);
+ } else {
+ dest.writeInt(0);
+ }
+ if (connections != null && !connections.isEmpty()) {
+ dest.writeInt(1);
+ dest.writeTypedArray(connections.values().toArray(
+ new ConnectionSettings[0]), flags);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mRingMode != null) {
+ dest.writeInt(1);
+ mRingMode.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mAirplaneMode != null) {
+ dest.writeInt(1);
+ mAirplaneMode.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mBrightness != null) {
+ dest.writeInt(1);
+ mBrightness.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ if (mScreenLockMode != null) {
+ dest.writeInt(1);
+ mScreenLockMode.writeToParcel(dest, 0);
+ } else {
+ dest.writeInt(0);
+ }
+ dest.writeTypedArray(mTriggers.values().toArray(new ProfileTrigger[0]), flags);
+ dest.writeInt(mExpandedDesktopMode);
+ dest.writeInt(mDozeMode);
+
+ // === ELDERBERRY ===
+ dest.writeInt(mNotificationLightMode);
+
+ if (networkConnectionSubIds != null && !networkConnectionSubIds.isEmpty()) {
+ dest.writeInt(1);
+ dest.writeTypedArray(networkConnectionSubIds.values().toArray(
+ new ConnectionSettings[0]), flags);
+ } else {
+ dest.writeInt(0);
+ }
+
+ // 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) {
+ if (in.readInt() != 0) {
+ mName = in.readString();
+ }
+ if (in.readInt() != 0) {
+ mNameResId = in.readInt();
+ }
+ if (in.readInt() != 0) {
+ mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid();
+ }
+ if (in.readInt() != 0) {
+ for (Parcelable parcel : in.readParcelableArray(null)) {
+ ParcelUuid u = (ParcelUuid) parcel;
+ mSecondaryUuids.add(u.getUuid());
+ }
+ }
+ mStatusBarIndicator = (in.readInt() == 1);
+ mProfileType = in.readInt();
+ mDirty = (in.readInt() == 1);
+ if (in.readInt() != 0) {
+ for (ProfileGroup group : in.createTypedArray(ProfileGroup.CREATOR)) {
+ profileGroups.put(group.getUuid(), group);
+ if (group.isDefaultGroup()) {
+ mDefaultGroup = group;
+ }
+ }
+ }
+ if (in.readInt() != 0) {
+ for (StreamSettings stream : in.createTypedArray(StreamSettings.CREATOR)) {
+ streams.put(stream.getStreamId(), stream);
+ }
+ }
+ if (in.readInt() != 0) {
+ for (ConnectionSettings connection :
+ in.createTypedArray(ConnectionSettings.CREATOR)) {
+ connections.put(connection.getConnectionId(), connection);
+ }
+ }
+ if (in.readInt() != 0) {
+ mRingMode = RingModeSettings.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ mAirplaneMode = AirplaneModeSettings.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ mBrightness = BrightnessSettings.CREATOR.createFromParcel(in);
+ }
+ if (in.readInt() != 0) {
+ mScreenLockMode = LockSettings.CREATOR.createFromParcel(in);
+ }
+ for (ProfileTrigger trigger : in.createTypedArray(ProfileTrigger.CREATOR)) {
+ mTriggers.put(trigger.mId, trigger);
+ }
+ mExpandedDesktopMode = in.readInt();
+ mDozeMode = in.readInt();
+ }
+ if (parcelableVersion >= Build.CM_VERSION_CODES.ELDERBERRY) {
+ mNotificationLightMode = in.readInt();
+ if (in.readInt() != 0) {
+ for (ConnectionSettings connection :
+ in.createTypedArray(ConnectionSettings.CREATOR)) {
+ // elderberry can do msim connections
+ networkConnectionSubIds.put(connection.getSubId(), connection);
+ }
+ }
+ }
+
+ // Complete the parcel info for the concierge
+ parcelInfo.complete();
+ }
+
+ /**
+ * Get the name associated with the {@link Profile}
+ * @return a string name of the profile
+ */
+ public String getName() {
+ return mName;
+ }
+
+ /**
+ * Set a name for the {@link Profile}
+ * @param name a string for the {@link Profile}
+ */
+ public void setName(String name) {
+ mName = name;
+ mNameResId = -1;
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link Type} of the {@link Profile}
+ * @return
+ */
+ public int getProfileType() {
+ return mProfileType;
+ }
+
+ /**
+ * Set the {@link Type} for the {@link Profile}
+ * @param type a type of profile
+ */
+ public void setProfileType(int type) {
+ mProfileType = type;
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link UUID} associated with the {@link Profile}
+ * @return the uuid for the profile
+ */
+ public UUID getUuid() {
+ if (this.mUuid == null) this.mUuid = UUID.randomUUID();
+ return this.mUuid;
+ }
+
+ /**
+ * Get the secondary {@link UUID}s for the {@link Profile}
+ * @return the secondary uuids for the Profile
+ */
+ public UUID[] getSecondaryUuids() {
+ return mSecondaryUuids.toArray(new UUID[mSecondaryUuids.size()]);
+ }
+
+ /**
+ * Set a list of secondary {@link UUID}s for the {@link Profile}
+ * @param uuids
+ */
+ public void setSecondaryUuids(List<UUID> uuids) {
+ mSecondaryUuids.clear();
+ if (uuids != null) {
+ mSecondaryUuids.addAll(uuids);
+ mDirty = true;
+ }
+ }
+
+ /**
+ * Add a secondary {@link UUID} to the {@link Profile}
+ * @param uuid
+ */
+ public void addSecondaryUuid(UUID uuid) {
+ if (uuid != null) {
+ mSecondaryUuids.add(uuid);
+ mDirty = true;
+ }
+ }
+
+ /**
+ * @hide
+ */
+ public boolean getStatusBarIndicator() {
+ return mStatusBarIndicator;
+ }
+
+ /**
+ * @hide
+ */
+ public void setStatusBarIndicator(boolean newStatusBarIndicator) {
+ mStatusBarIndicator = newStatusBarIndicator;
+ mDirty = true;
+ }
+
+ /**
+ * Check if the given {@link Profile} is a {@link Type#CONDITIONAL}
+ * @return true if conditional
+ */
+ public boolean isConditionalType() {
+ return(mProfileType == Type.CONDITIONAL ? true : false);
+ }
+
+ /**
+ * @hide
+ */
+ public void setConditionalType() {
+ mProfileType = Type.CONDITIONAL;
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link RingModeSettings} for the {@link Profile}
+ * @return
+ */
+ public RingModeSettings getRingMode() {
+ return mRingMode;
+ }
+
+ /**
+ * Set the {@link RingModeSettings} for the {@link Profile}
+ * @param descriptor
+ */
+ public void setRingMode(RingModeSettings descriptor) {
+ mRingMode = descriptor;
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link LockSettings} for the {@link Profile}
+ * @return
+ */
+ public LockSettings getScreenLockMode() {
+ return mScreenLockMode;
+ }
+
+ /**
+ * Set the {@link LockSettings} for the {@link Profile}
+ * @param screenLockMode
+ */
+ public void setScreenLockMode(LockSettings screenLockMode) {
+ mScreenLockMode = screenLockMode;
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link ExpandedDesktopMode} for the {@link Profile}
+ * @return
+ */
+ public int getExpandedDesktopMode() {
+ return mExpandedDesktopMode;
+ }
+
+ /**
+ * Set the {@link ExpandedDesktopMode} for the {@link Profile}
+ * @return
+ */
+ public void setExpandedDesktopMode(int expandedDesktopMode) {
+ if (expandedDesktopMode < ExpandedDesktopMode.DEFAULT
+ || expandedDesktopMode > ExpandedDesktopMode.DISABLE) {
+ mExpandedDesktopMode = ExpandedDesktopMode.DEFAULT;
+ } else {
+ mExpandedDesktopMode = expandedDesktopMode;
+ }
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link DozeMode} associated with the {@link Profile}
+ * @return
+ */
+ public int getDozeMode() {
+ return mDozeMode;
+ }
+
+ /**
+ * Set the {@link DozeMode} associated with the {@link Profile}
+ * @return
+ */
+ public void setDozeMode(int dozeMode) {
+ if (dozeMode < DozeMode.DEFAULT
+ || dozeMode > DozeMode.DISABLE) {
+ mDozeMode = DozeMode.DEFAULT;
+ } else {
+ mDozeMode = dozeMode;
+ }
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link NotificationLightMode} associated with the {@link Profile}
+ * @return
+ */
+ public int getNotificationLightMode() {
+ return mNotificationLightMode;
+ }
+
+ /**
+ * Set the {@link NotificationLightMode} associated with the {@link Profile}
+ * @return
+ */
+ public void setNotificationLightMode(int notificationLightMode) {
+ if (notificationLightMode < NotificationLightMode.DEFAULT
+ || notificationLightMode > NotificationLightMode.DISABLE) {
+ mNotificationLightMode = NotificationLightMode.DEFAULT;
+ } else {
+ mNotificationLightMode = notificationLightMode;
+ }
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link AirplaneModeSettings} associated with the {@link Profile}
+ * @return
+ */
+ public AirplaneModeSettings getAirplaneMode() {
+ return mAirplaneMode;
+ }
+
+ /**
+ * Set the {@link AirplaneModeSettings} associated with the {@link Profile}
+ * @param descriptor
+ */
+ public void setAirplaneMode(AirplaneModeSettings descriptor) {
+ mAirplaneMode = descriptor;
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link BrightnessSettings} associated with the {@link Profile}
+ * @return
+ */
+ public BrightnessSettings getBrightness() {
+ return mBrightness;
+ }
+
+ /**
+ * Set the {@link BrightnessSettings} associated with the {@link Profile}
+ * @return
+ */
+ public void setBrightness(BrightnessSettings descriptor) {
+ mBrightness = descriptor;
+ mDirty = true;
+ }
+
+ /** @hide */
+ public boolean isDirty() {
+ if (mDirty) {
+ return true;
+ }
+ for (ProfileGroup group : profileGroups.values()) {
+ if (group.isDirty()) {
+ return true;
+ }
+ }
+ for (StreamSettings stream : streams.values()) {
+ if (stream.isDirty()) {
+ return true;
+ }
+ }
+ for (ConnectionSettings conn : connections.values()) {
+ if (conn.isDirty()) {
+ return true;
+ }
+ }
+ for (ConnectionSettings conn : networkConnectionSubIds.values()) {
+ if (conn.isDirty()) {
+ return true;
+ }
+ }
+ if (mRingMode.isDirty()) {
+ return true;
+ }
+ if (mAirplaneMode.isDirty()) {
+ return true;
+ }
+ if (mBrightness.isDirty()) {
+ return true;
+ }
+ return false;
+ }
+
+ /** @hide */
+ public void getXmlString(StringBuilder builder, Context context) {
+ builder.append("<profile ");
+ if (mNameResId > 0) {
+ builder.append("nameres=\"");
+ builder.append(context.getResources().getResourceEntryName(mNameResId));
+ } else {
+ builder.append("name=\"");
+ builder.append(TextUtils.htmlEncode(getName()));
+ }
+ builder.append("\" uuid=\"");
+ builder.append(TextUtils.htmlEncode(getUuid().toString()));
+ builder.append("\">\n");
+
+ builder.append("<uuids>");
+ for (UUID u : mSecondaryUuids) {
+ builder.append("<uuid>");
+ builder.append(TextUtils.htmlEncode(u.toString()));
+ builder.append("</uuid>");
+ }
+ builder.append("</uuids>\n");
+
+ builder.append("<profiletype>");
+ builder.append(getProfileType() == Type.TOGGLE ? "toggle" : "conditional");
+ builder.append("</profiletype>\n");
+
+ builder.append("<statusbar>");
+ builder.append(getStatusBarIndicator() ? "yes" : "no");
+ builder.append("</statusbar>\n");
+
+ if (mScreenLockMode != null) {
+ builder.append("<screen-lock-mode>");
+ mScreenLockMode.writeXmlString(builder, context);
+ builder.append("</screen-lock-mode>\n");
+ }
+
+ builder.append("<expanded-desktop-mode>");
+ builder.append(mExpandedDesktopMode);
+ builder.append("</expanded-desktop-mode>\n");
+
+ builder.append("<doze-mode>");
+ builder.append(mDozeMode);
+ builder.append("</doze-mode>\n");
+
+ builder.append("<notification-light-mode>");
+ builder.append(mNotificationLightMode);
+ builder.append("</notification-light-mode>\n");
+
+ mAirplaneMode.getXmlString(builder, context);
+
+ mBrightness.getXmlString(builder, context);
+
+ mRingMode.getXmlString(builder, context);
+
+ for (ProfileGroup pGroup : profileGroups.values()) {
+ pGroup.getXmlString(builder, context);
+ }
+ for (StreamSettings sd : streams.values()) {
+ sd.getXmlString(builder, context);
+ }
+ for (ConnectionSettings cs : connections.values()) {
+ cs.getXmlString(builder, context);
+ }
+ for (ConnectionSettings cs : networkConnectionSubIds.values()) {
+ cs.getXmlString(builder, context);
+ }
+ if (!mTriggers.isEmpty()) {
+ builder.append("<triggers>\n");
+ for (ProfileTrigger trigger : mTriggers.values()) {
+ trigger.getXmlString(builder, context);
+ }
+ builder.append("</triggers>\n");
+ }
+
+ builder.append("</profile>\n");
+ mDirty = false;
+ }
+
+ private static List<UUID> readSecondaryUuidsFromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException,
+ IOException {
+ ArrayList<UUID> uuids = new ArrayList<UUID>();
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("uuids")) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("uuid")) {
+ try {
+ uuids.add(UUID.fromString(xpp.nextText()));
+ } catch (NullPointerException e) {
+ Log.w(TAG, "Null Pointer - invalid UUID");
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG, "UUID not recognized");
+ }
+ }
+ }
+ event = xpp.next();
+ }
+ return uuids;
+ }
+
+ private static void readTriggersFromXml(XmlPullParser xpp, Context context, Profile profile)
+ throws XmlPullParserException, IOException {
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG || !xpp.getName().equals("triggers")) {
+ if (event == XmlPullParser.START_TAG) {
+ ProfileTrigger trigger = ProfileTrigger.fromXml(xpp, context);
+ if (trigger != null) {
+ profile.mTriggers.put(trigger.mId, trigger);
+ }
+ } else if (event == XmlPullParser.END_DOCUMENT) {
+ throw new IOException("Premature end of file while parsing triggers");
+ }
+ event = xpp.next();
+ }
+ }
+
+ /** @hide */
+ public void validateRingtones(Context context) {
+ for (ProfileGroup pg : profileGroups.values()) {
+ pg.validateOverrideUris(context);
+ }
+ }
+
+ /** @hide */
+ public static Profile fromXml(XmlPullParser xpp, Context context)
+ throws XmlPullParserException, IOException {
+ String value = xpp.getAttributeValue(null, "nameres");
+ int profileNameResId = -1;
+ String profileName = null;
+
+ if (value != null) {
+ profileNameResId = context.getResources().getIdentifier(value, "string",
+ "cyanogenmod.platform");
+ if (profileNameResId > 0) {
+ profileName = context.getResources().getString(profileNameResId);
+ }
+ }
+
+ if (profileName == null) {
+ profileName = xpp.getAttributeValue(null, "name");
+ }
+
+ UUID profileUuid = UUID.randomUUID();
+ try {
+ profileUuid = UUID.fromString(xpp.getAttributeValue(null, "uuid"));
+ } catch (NullPointerException e) {
+ Log.w(TAG,
+ "Null Pointer - UUID not found for "
+ + profileName
+ + ". New UUID generated: "
+ + profileUuid.toString()
+ );
+ } catch (IllegalArgumentException e) {
+ Log.w(TAG,
+ "UUID not recognized for "
+ + profileName
+ + ". New UUID generated: "
+ + profileUuid.toString()
+ );
+ }
+
+ Profile profile = new Profile(profileName, profileNameResId, profileUuid);
+ int event = xpp.next();
+ while (event != XmlPullParser.END_TAG) {
+ if (event == XmlPullParser.START_TAG) {
+ String name = xpp.getName();
+ if (name.equals("uuids")) {
+ profile.setSecondaryUuids(readSecondaryUuidsFromXml(xpp, context));
+ }
+ if (name.equals("statusbar")) {
+ profile.setStatusBarIndicator(xpp.nextText().equals("yes"));
+ }
+ if (name.equals("profiletype")) {
+ profile.setProfileType(xpp.nextText().equals("toggle")
+ ? Type.TOGGLE : Type.CONDITIONAL);
+ }
+ if (name.equals("ringModeDescriptor")) {
+ RingModeSettings smd = RingModeSettings.fromXml(xpp, context);
+ profile.setRingMode(smd);
+ }
+ if (name.equals("airplaneModeDescriptor")) {
+ AirplaneModeSettings amd = AirplaneModeSettings.fromXml(xpp, context);
+ profile.setAirplaneMode(amd);
+ }
+ if (name.equals("brightnessDescriptor")) {
+ BrightnessSettings bd = BrightnessSettings.fromXml(xpp, context);
+ profile.setBrightness(bd);
+ }
+ if (name.equals("screen-lock-mode")) {
+ LockSettings lockMode = new LockSettings(Integer.valueOf(xpp.nextText()));
+ profile.setScreenLockMode(lockMode);
+ }
+ if (name.equals("expanded-desktop-mode")) {
+ profile.setExpandedDesktopMode(Integer.valueOf(xpp.nextText()));
+ }
+ if (name.equals("doze-mode")) {
+ profile.setDozeMode(Integer.valueOf(xpp.nextText()));
+ }
+ if (name.equals("notification-light-mode")) {
+ profile.setNotificationLightMode(Integer.valueOf(xpp.nextText()));
+ }
+ if (name.equals("profileGroup")) {
+ ProfileGroup pg = ProfileGroup.fromXml(xpp, context);
+ profile.addProfileGroup(pg);
+ }
+ if (name.equals("streamDescriptor")) {
+ StreamSettings sd = StreamSettings.fromXml(xpp, context);
+ profile.setStreamSettings(sd);
+ }
+ if (name.equals("connectionDescriptor")) {
+ ConnectionSettings cs = ConnectionSettings.fromXml(xpp, context);
+ if (Build.CM_VERSION.SDK_INT >= Build.CM_VERSION_CODES.ELDERBERRY
+ && cs.getConnectionId() == ConnectionSettings.PROFILE_CONNECTION_2G3G4G) {
+ profile.networkConnectionSubIds.put(cs.getSubId(), cs);
+ } else {
+ profile.connections.put(cs.getConnectionId(), cs);
+ }
+ }
+ if (name.equals("triggers")) {
+ readTriggersFromXml(xpp, context, profile);
+ }
+ } else if (event == XmlPullParser.END_DOCUMENT) {
+ throw new IOException("Premature end of file while parsing profle:" + profileName);
+ }
+ event = xpp.next();
+ }
+
+ /* we just loaded from XML, so nothing needs saving */
+ profile.mDirty = false;
+
+ return profile;
+ }
+
+ /** @hide */
+ public void doSelect(Context context, IKeyguardService keyguardService) {
+ // Set stream volumes
+ AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
+ for (StreamSettings sd : streams.values()) {
+ if (sd.isOverride()) {
+ am.setStreamVolume(sd.getStreamId(), sd.getValue(), 0);
+ }
+ }
+ // Set connections
+ for (ConnectionSettings cs : connections.values()) {
+ if (cs.isOverride()) {
+ cs.processOverride(context);
+ }
+ }
+ for (ConnectionSettings cs : networkConnectionSubIds.values()) {
+ if (cs.isOverride()) {
+ cs.processOverride(context);
+ }
+ }
+
+ // Set ring mode
+ mRingMode.processOverride(context);
+ // Set airplane mode
+ mAirplaneMode.processOverride(context);
+
+ // Set brightness
+ mBrightness.processOverride(context);
+
+ if (keyguardService != null) {
+ // Set lock screen mode
+ mScreenLockMode.processOverride(context, keyguardService);
+ } else {
+ Log.e(TAG, "cannot process screen lock override without a keyguard service.");
+ }
+
+ // Set expanded desktop
+ // if (mExpandedDesktopMode != ExpandedDesktopMode.DEFAULT) {
+ // Settings.System.putIntForUser(context.getContentResolver(),
+ // Settings.System.EXPANDED_DESKTOP_STATE,
+ // mExpandedDesktopMode == ExpandedDesktopMode.ENABLE ? 1 : 0,
+ // UserHandle.USER_CURRENT);
+ // }
+
+ // Set doze mode
+ if (mDozeMode != DozeMode.DEFAULT) {
+ Settings.Secure.putIntForUser(context.getContentResolver(),
+ Settings.Secure.DOZE_ENABLED,
+ mDozeMode == DozeMode.ENABLE ? 1 : 0,
+ UserHandle.USER_CURRENT);
+ }
+
+ // Set notification light mode
+ if (mNotificationLightMode != NotificationLightMode.DEFAULT) {
+ Settings.System.putIntForUser(context.getContentResolver(),
+ Settings.System.NOTIFICATION_LIGHT_PULSE,
+ mNotificationLightMode == NotificationLightMode.ENABLE ? 1 : 0,
+ UserHandle.USER_CURRENT);
+ }
+ }
+
+ /**
+ * Get the settings for a stream id in the {@link Profile}
+ * @return {@link StreamSettings}
+ */
+ public StreamSettings getSettingsForStream(int streamId){
+ return streams.get(streamId);
+ }
+
+ /**
+ * Set the {@link StreamSettings} for the {@link Profile}
+ * @param descriptor
+ */
+ public void setStreamSettings(StreamSettings descriptor){
+ streams.put(descriptor.getStreamId(), descriptor);
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link StreamSettings} for the {@link Profile}
+ * @return {@link Collection<StreamSettings>}
+ */
+ public Collection<StreamSettings> getStreamSettings(){
+ return streams.values();
+ }
+
+ /**
+ * Get the settings for a connection id in the {@link Profile}
+ * @return {@link ConnectionSettings}
+ */
+ public ConnectionSettings getSettingsForConnection(int connectionId){
+ if (connectionId == ConnectionSettings.PROFILE_CONNECTION_2G3G4G) {
+ if (networkConnectionSubIds.size() > 1) {
+ throw new UnsupportedOperationException("Use getConnectionSettingsWithSubId for MSIM devices!");
+ } else {
+ return networkConnectionSubIds.values().iterator().next();
+ }
+ }
+ return connections.get(connectionId);
+ }
+
+ /**
+ * Get the settings for a {@link ConnectionSettings#PROFILE_CONNECTION_2G3G4G} by sub id.
+ *
+ * @param subId the sub id to lookup. Can be {@link android.telephony.SubscriptionManager#INVALID_SUBSCRIPTION_ID}
+ * @return {@link ConnectionSettings}
+ */
+ public ConnectionSettings getConnectionSettingWithSubId(int subId) {
+ return networkConnectionSubIds.get(subId);
+ }
+
+ /**
+ * Set the {@link ConnectionSettings} for the {@link Profile}
+ * @param descriptor
+ */
+ public void setConnectionSettings(ConnectionSettings descriptor) {
+ if (descriptor.getConnectionId() == ConnectionSettings.PROFILE_CONNECTION_2G3G4G) {
+ networkConnectionSubIds.put(descriptor.getSubId(), descriptor);
+ } else {
+ connections.put(descriptor.getConnectionId(), descriptor);
+ }
+ mDirty = true;
+ }
+
+ /**
+ * Get the {@link ConnectionSettings} for the {@link Profile}
+ * @return {@link Collection<ConnectionSettings>}
+ */
+ public Collection<ConnectionSettings> getConnectionSettings(){
+ List<ConnectionSettings> combinedList = new ArrayList<>();
+ combinedList.addAll(connections.values());
+ combinedList.addAll(networkConnectionSubIds.values());
+ return combinedList;
+ }
+}