diff options
Diffstat (limited to 'core/java/android')
20 files changed, 3174 insertions, 21 deletions
diff --git a/core/java/android/app/ConnectionSettings.java b/core/java/android/app/ConnectionSettings.java new file mode 100755 index 0000000..00af439 --- /dev/null +++ b/core/java/android/app/ConnectionSettings.java @@ -0,0 +1,216 @@ +package android.app; + +import android.bluetooth.BluetoothAdapter; +import android.content.ContentResolver; +import android.content.Context; +import android.location.LocationManager; +import android.net.ConnectivityManager; +import android.net.wifi.WifiManager; +import android.net.wimax.WimaxHelper; +import android.os.Parcel; +import android.os.Parcelable; +import android.provider.Settings; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import java.io.IOException; + +/** @hide */ +public final class ConnectionSettings implements Parcelable { + + private int mConnectionId; + private int mValue; + private boolean mOverride; + private boolean mDirty; + + public static final int PROFILE_CONNECTION_MOBILEDATA = 0; + public static final int PROFILE_CONNECTION_WIFI = 1; + public static final int PROFILE_CONNECTION_WIFIAP = 2; + public static final int PROFILE_CONNECTION_WIMAX = 3; + public static final int PROFILE_CONNECTION_GPS = 4; + public static final int PROFILE_CONNECTION_SYNC = 5; + public static final int PROFILE_CONNECTION_BLUETOOTH = 7; + + /** @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]; + } + }; + + + public ConnectionSettings(Parcel parcel) { + readFromParcel(parcel); + } + + public ConnectionSettings(int connectionId) { + this(connectionId, 0, false); + } + + public ConnectionSettings(int connectionId, int value, boolean override) { + mConnectionId = connectionId; + mValue = value; + mOverride = override; + mDirty = false; + } + + public int getConnectionId() { + return mConnectionId; + } + + public int getValue() { + return mValue; + } + + public void setValue(int value) { + mValue = value; + mDirty = true; + } + + public void setOverride(boolean override) { + mOverride = override; + mDirty = true; + } + + public boolean isOverride() { + return mOverride; + } + + /** @hide */ + public boolean isDirty() { + return mDirty; + } + + 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); + ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE); + + boolean forcedState = getValue() == 1; + boolean currentState; + + switch (getConnectionId()) { + case PROFILE_CONNECTION_MOBILEDATA: + currentState = cm.getMobileDataEnabled(); + if (forcedState != currentState) { + cm.setMobileDataEnabled(forcedState); + } + break; + case PROFILE_CONNECTION_BLUETOOTH: + currentState = bta.isEnabled(); + if (forcedState && !currentState) { + bta.enable(); + } else if (!forcedState && currentState) { + 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; + } + } + + /** @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()); + } + } + 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</connectionDescriptor>\n"); + } + + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mConnectionId); + dest.writeInt(mOverride ? 1 : 0); + dest.writeInt(mValue); + dest.writeInt(mDirty ? 1 : 0); + } + + /** @hide */ + public void readFromParcel(Parcel in) { + mConnectionId = in.readInt(); + mOverride = in.readInt() != 0; + mValue = in.readInt(); + mDirty = in.readInt() != 0; + } + + +} diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java index 95b6bed..20ed560 100644 --- a/core/java/android/app/ContextImpl.java +++ b/core/java/android/app/ContextImpl.java @@ -535,6 +535,12 @@ class ContextImpl extends Context { IUserManager service = IUserManager.Stub.asInterface(b); return new UserManager(ctx, service); }}); + + registerService(PROFILE_SERVICE, new ServiceFetcher() { + public Object createService(ContextImpl ctx) { + final Context outerContext = ctx.getOuterContext(); + return new ProfileManager (outerContext, ctx.mMainThread.getHandler()); + }}); } static ContextImpl getImpl(Context context) { diff --git a/core/java/android/app/IProfileManager.aidl b/core/java/android/app/IProfileManager.aidl new file mode 100644 index 0000000..c7c6744 --- /dev/null +++ b/core/java/android/app/IProfileManager.aidl @@ -0,0 +1,50 @@ +/* //device/java/android/android/app/IProfileManager.aidl +** +** Copyright 2007, The Android Open Source 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 android.app; + +import android.app.Profile; +import android.app.NotificationGroup; +import android.os.ParcelUuid; + +/** {@hide} */ +interface IProfileManager +{ + boolean setActiveProfile(in ParcelUuid profileParcelUuid); + boolean setActiveProfileByName(String profileName); + Profile getActiveProfile(); + + boolean addProfile(in Profile profile); + boolean removeProfile(in Profile profile); + void updateProfile(in Profile profile); + + Profile getProfile(in ParcelUuid profileParcelUuid); + Profile getProfileByName(String profileName); + Profile[] getProfiles(); + boolean profileExists(in ParcelUuid profileUuid); + boolean profileExistsByName(String profileName); + boolean notificationGroupExistsByName(String notificationGroupName); + + NotificationGroup[] getNotificationGroups(); + void addNotificationGroup(in NotificationGroup group); + void removeNotificationGroup(in NotificationGroup group); + void updateNotificationGroup(in NotificationGroup group); + NotificationGroup getNotificationGroupForPackage(in String pkg); + NotificationGroup getNotificationGroup(in ParcelUuid groupParcelUuid); + + void resetAll(); +} diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java index e79b214..238a63e 100644 --- a/core/java/android/app/Notification.java +++ b/core/java/android/app/Notification.java @@ -437,6 +437,15 @@ public class Notification implements Parcelable */ public static final String EXTRA_PEOPLE = "android.people"; + /** + * Bit to be bitwise-ored into the {@link #flags} field that should be + * set if this notification should force the led to pulse even if the + * screen has been shut off while the notification was active. + * + * @hide + */ + public static final int FLAG_FORCE_LED_SCREEN_OFF = 0x00000100; + private Bundle extras; /** diff --git a/core/java/android/app/NotificationGroup.aidl b/core/java/android/app/NotificationGroup.aidl new file mode 100644 index 0000000..44b6290 --- /dev/null +++ b/core/java/android/app/NotificationGroup.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2012, 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 android.app; + +parcelable NotificationGroup; diff --git a/core/java/android/app/NotificationGroup.java b/core/java/android/app/NotificationGroup.java new file mode 100644 index 0000000..bcb70d3 --- /dev/null +++ b/core/java/android/app/NotificationGroup.java @@ -0,0 +1,201 @@ +/* + * Copyright (C) 2011 The Android Open Source 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 android.app; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelUuid; +import android.os.RemoteException; +import android.text.TextUtils; +import android.util.Log; + +import java.io.IOException; +import java.util.Arrays; +import java.util.HashSet; +import java.util.Set; +import java.util.UUID; + +/** @hide */ +public class NotificationGroup implements Parcelable { + private static final String TAG = "NotificationGroup"; + + private String mName; + private int mNameResId; + + private UUID mUuid; + + private Set<String> mPackages = new HashSet<String>(); + + private boolean mDirty; + + public static final Parcelable.Creator<NotificationGroup> CREATOR = new Parcelable.Creator<NotificationGroup>() { + public NotificationGroup createFromParcel(Parcel in) { + return new NotificationGroup(in); + } + + @Override + public NotificationGroup[] newArray(int size) { + return new NotificationGroup[size]; + } + }; + + public NotificationGroup(String name) { + this(name, -1, null); + } + + public NotificationGroup(String name, int nameResId, UUID uuid) { + mName = name; + mNameResId = nameResId; + mUuid = (uuid != null) ? uuid : UUID.randomUUID(); + mDirty = uuid == null; + } + + private NotificationGroup(Parcel in) { + readFromParcel(in); + } + + @Override + public String toString() { + return getName(); + } + + public String getName() { + return mName; + } + + public void setName(String name) { + mName = name; + mNameResId = -1; + mDirty = true; + } + + public UUID getUuid() { + return mUuid; + } + + public void addPackage(String pkg) { + mPackages.add(pkg); + mDirty = true; + } + + public String[] getPackages() { + return mPackages.toArray(new String[mPackages.size()]); + } + + public void removePackage(String pkg) { + mPackages.remove(pkg); + mDirty = true; + } + + public boolean hasPackage(String pkg) { + return mPackages.contains(pkg); + } + + public boolean isDirty() { + return mDirty; + } + + @Override + public int describeContents() { + return 0; + } + + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mName); + dest.writeInt(mNameResId); + dest.writeInt(mDirty ? 1 : 0); + new ParcelUuid(mUuid).writeToParcel(dest, 0); + dest.writeStringArray(getPackages()); + } + + public void readFromParcel(Parcel in) { + mName = in.readString(); + mNameResId = in.readInt(); + mDirty = in.readInt() != 0; + mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid(); + mPackages.addAll(Arrays.asList(in.readStringArray())); + } + + public void getXmlString(StringBuilder builder, Context context) { + builder.append("<notificationGroup "); + 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"); + for (String pkg : mPackages) { + builder.append("<package>" + TextUtils.htmlEncode(pkg) + "</package>\n"); + } + builder.append("</notificationGroup>\n"); + mDirty = false; + } + + public static NotificationGroup fromXml(XmlPullParser xpp, Context context) + throws XmlPullParserException, IOException { + String value = xpp.getAttributeValue(null, "nameres"); + int nameResId = -1; + String name = null; + UUID uuid = null; + + if (value != null) { + nameResId = context.getResources().getIdentifier(value, "string", "android"); + if (nameResId > 0) { + name = context.getResources().getString(nameResId); + } + } + + if (name == null) { + name = xpp.getAttributeValue(null, "name"); + } + + value = xpp.getAttributeValue(null, "uuid"); + if (value != null) { + try { + uuid = UUID.fromString(value); + } catch (IllegalArgumentException e) { + Log.w(TAG, "UUID not recognized for " + name + ", using new one."); + } + } + + NotificationGroup notificationGroup = new NotificationGroup(name, nameResId, uuid); + int event = xpp.next(); + while (event != XmlPullParser.END_TAG || !xpp.getName().equals("notificationGroup")) { + if (event == XmlPullParser.START_TAG) { + if (xpp.getName().equals("package")) { + String pkg = xpp.nextText(); + notificationGroup.addPackage(pkg); + } + } + event = xpp.next(); + } + + /* we just loaded from XML, no need to save */ + notificationGroup.mDirty = false; + + return notificationGroup; + } +} diff --git a/core/java/android/app/Profile.aidl b/core/java/android/app/Profile.aidl new file mode 100644 index 0000000..d75bd76 --- /dev/null +++ b/core/java/android/app/Profile.aidl @@ -0,0 +1,19 @@ +/** + * Copyright (c) 2007, The Android Open Source 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 android.app; + +parcelable Profile; diff --git a/core/java/android/app/Profile.java b/core/java/android/app/Profile.java new file mode 100644 index 0000000..54e187d --- /dev/null +++ b/core/java/android/app/Profile.java @@ -0,0 +1,595 @@ +/* + * Copyright (C) 2011 The Android Open Source 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 android.app; + +import android.content.Context; +import android.content.Intent; +import android.media.AudioManager; +import android.os.Parcel; +import android.os.ParcelUuid; +import android.os.Parcelable; +import android.provider.Settings; +import android.text.TextUtils; +import android.util.Log; + +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.UUID; + +/** + * @hide + */ +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 static final int CONDITIONAL_TYPE = 1; + + private static final int TOGGLE_TYPE = 0; + + private Map<Integer, StreamSettings> streams = new HashMap<Integer, StreamSettings>(); + + private Map<Integer, ConnectionSettings> connections = new HashMap<Integer, ConnectionSettings>(); + + private Map<Integer, VibratorSettings> vibrators = new HashMap<Integer, VibratorSettings>(); + + private int mScreenLockMode = LockMode.DEFAULT; + + private int mAirplaneMode = AirplaneMode.DEFAULT; + + /** @hide */ + public static class LockMode { + public static final int DEFAULT = 0; + public static final int INSECURE = 1; + public static final int DISABLE = 2; + } + + /** @hide */ + public static class AirplaneMode { + public static final int DEFAULT = 0; + public static final int ENABLE = 1; + public static final int DISABLE = 2; + } + + /** @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]; + } + }; + + /** @hide */ + public Profile(String name) { + this(name, -1, UUID.randomUUID()); + } + + private Profile(String name, int nameResId, UUID uuid) { + mName = name; + mNameResId = nameResId; + mUuid = uuid; + mProfileType = TOGGLE_TYPE; //Default to toggle type + mDirty = false; + } + + private Profile(Parcel in) { + readFromParcel(in); + } + + 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; + } + + /** @hide */ + public void addProfileGroup(ProfileGroup value) { + if (value.isDefaultGroup()) { + /* we must not have more than one default group */ + if (mDefaultGroup != null) { + return; + } + mDefaultGroup = value; + } + profileGroups.put(value.getUuid(), value); + mDirty = true; + } + + /** @hide */ + public void removeProfileGroup(UUID uuid) { + if (!profileGroups.get(uuid).isDefaultGroup()) { + profileGroups.remove(uuid); + } else { + Log.e(TAG, "Cannot remove default group: " + uuid); + } + } + + public ProfileGroup[] getProfileGroups() { + return profileGroups.values().toArray(new ProfileGroup[profileGroups.size()]); + } + + public ProfileGroup getProfileGroup(UUID uuid) { + return profileGroups.get(uuid); + } + + public ProfileGroup getDefaultGroup() { + return mDefaultGroup; + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mName); + dest.writeInt(mNameResId); + new ParcelUuid(mUuid).writeToParcel(dest, 0); + ArrayList<ParcelUuid> uuids = new ArrayList<ParcelUuid>(mSecondaryUuids.size()); + for (UUID u : mSecondaryUuids) { + uuids.add(new ParcelUuid(u)); + } + dest.writeParcelableArray(uuids.toArray(new Parcelable[uuids.size()]), flags); + dest.writeInt(mStatusBarIndicator ? 1 : 0); + dest.writeInt(mProfileType); + dest.writeInt(mDirty ? 1 : 0); + dest.writeParcelableArray( + profileGroups.values().toArray(new Parcelable[profileGroups.size()]), flags); + dest.writeParcelableArray( + streams.values().toArray(new Parcelable[streams.size()]), flags); + dest.writeParcelableArray( + connections.values().toArray(new Parcelable[connections.size()]), flags); + dest.writeParcelableArray(vibrators.values().toArray(new Parcelable[vibrators.size()]), flags); + dest.writeInt(mScreenLockMode); + dest.writeInt(mAirplaneMode); + } + + /** @hide */ + public void readFromParcel(Parcel in) { + mName = in.readString(); + mNameResId = in.readInt(); + mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid(); + 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); + for (Parcelable group : in.readParcelableArray(null)) { + ProfileGroup grp = (ProfileGroup) group; + profileGroups.put(grp.getUuid(), grp); + if (grp.isDefaultGroup()) { + mDefaultGroup = grp; + } + } + for (Parcelable parcel : in.readParcelableArray(null)) { + StreamSettings stream = (StreamSettings) parcel; + streams.put(stream.getStreamId(), stream); + } + for (Parcelable parcel : in.readParcelableArray(null)) { + ConnectionSettings connection = (ConnectionSettings) parcel; + connections.put(connection.getConnectionId(), connection); + } + for (Parcelable parcel : in.readParcelableArray(null)) { + VibratorSettings vibrator = (VibratorSettings) parcel; + vibrators.put(vibrator.getVibratorId(), vibrator); + } + mScreenLockMode = in.readInt(); + mAirplaneMode = in.readInt(); + } + + public String getName() { + return mName; + } + + /** @hide */ + public void setName(String name) { + mName = name; + mNameResId = -1; + mDirty = true; + } + + public int getProfileType() { + return mProfileType; + } + + /** @hide */ + public void setProfileType(int type) { + mProfileType = type; + mDirty = true; + } + + public UUID getUuid() { + if (this.mUuid == null) this.mUuid = UUID.randomUUID(); + return this.mUuid; + } + + public UUID[] getSecondaryUuids() { + return mSecondaryUuids.toArray(new UUID[mSecondaryUuids.size()]); + } + + public void setSecondaryUuids(List<UUID> uuids) { + mSecondaryUuids.clear(); + if (uuids != null) { + mSecondaryUuids.addAll(uuids); + mDirty = true; + } + } + + public void addSecondaryUuid(UUID uuid) { + if (uuid != null) { + mSecondaryUuids.add(uuid); + mDirty = true; + } + } + + public boolean getStatusBarIndicator() { + return mStatusBarIndicator; + } + + public void setStatusBarIndicator(boolean newStatusBarIndicator) { + mStatusBarIndicator = newStatusBarIndicator; + mDirty = true; + } + + public boolean isConditionalType() { + return(mProfileType == CONDITIONAL_TYPE ? true : false); + } + + public void setConditionalType() { + mProfileType = CONDITIONAL_TYPE; + mDirty = true; + } + + public int getScreenLockMode() { + return mScreenLockMode; + } + + public void setScreenLockMode(int screenLockMode) { + if (screenLockMode < LockMode.DEFAULT || screenLockMode > LockMode.DISABLE) { + mScreenLockMode = LockMode.DEFAULT; + } else { + mScreenLockMode = screenLockMode; + } + mDirty = true; + } + + public int getAirplaneMode() { + return mAirplaneMode; + } + + public void setAirplaneMode(int airplaneMode) { + if (airplaneMode < AirplaneMode.DEFAULT || airplaneMode > AirplaneMode.DISABLE) { + mAirplaneMode = AirplaneMode.DEFAULT; + } else { + mAirplaneMode = airplaneMode; + } + 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 (VibratorSettings vibrator : vibrators.values()) { + if (vibrator.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() == TOGGLE_TYPE ? "toggle" : "conditional"); + builder.append("</profiletype>\n"); + + builder.append("<statusbar>"); + builder.append(getStatusBarIndicator() ? "yes" : "no"); + builder.append("</statusbar>\n"); + + builder.append("<screen-lock-mode>"); + builder.append(mScreenLockMode); + builder.append("</screen-lock-mode>\n"); + + builder.append("<airplane-mode>"); + builder.append(mAirplaneMode); + builder.append("</airplane-mode>\n"); + + 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 (VibratorSettings vs : vibrators.values()) { + vs.getXmlString(builder, context); + } + 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; + } + + /** @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", "android"); + 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") ? TOGGLE_TYPE : CONDITIONAL_TYPE); + } + if (name.equals("screen-lock-mode")) { + profile.setScreenLockMode(Integer.valueOf(xpp.nextText())); + } + if (name.equals("airplane-mode")) { + profile.setAirplaneMode(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); + profile.connections.put(cs.getConnectionId(), cs); + } + if (name.equals("vibratorDescriptor")) { + VibratorSettings vs = VibratorSettings.fromXml(xpp, context); + profile.setVibratorSettings(vs); + } + } + event = xpp.next(); + } + + /* we just loaded from XML, so nothing needs saving */ + profile.mDirty = false; + + return profile; + } + + /** @hide */ + public void doSelect(Context context) { + // 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); + } + } + // Set vibrators + for (VibratorSettings vs : vibrators.values()) { + if (vs.isOverride()) { + vs.processOverride(context); + } + } + // Set airplane mode + doSelectAirplaneMode(context); + } + + private void doSelectAirplaneMode(Context context) { + if (getAirplaneMode() != AirplaneMode.DEFAULT) { + int current = Settings.System.getInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 0); + int target = getAirplaneMode(); + if (current == 1 && target == AirplaneMode.DISABLE || current == 0 && target == AirplaneMode.ENABLE) { + Settings.System.putInt(context.getContentResolver(), Settings.System.AIRPLANE_MODE_ON, 1 - current); + Intent intent = new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED); + intent.putExtra("state", target != AirplaneMode.DISABLE); + context.sendBroadcast(intent); + } + } + } + + /** @hide */ + public StreamSettings getSettingsForStream(int streamId){ + return streams.get(streamId); + } + + /** @hide */ + public void setStreamSettings(StreamSettings descriptor){ + streams.put(descriptor.getStreamId(), descriptor); + mDirty = true; + } + + /** @hide */ + public Collection<StreamSettings> getStreamSettings(){ + return streams.values(); + } + + /** @hide */ + public VibratorSettings getSettingsForVibrator(int vibratorId) { + return vibrators.get(vibratorId); + } + + /** @hide */ + public void setVibratorSettings(VibratorSettings descriptor) { + vibrators.put(descriptor.getVibratorId(), descriptor); + mDirty = true; + } + + /** @hide */ + public Collection<VibratorSettings> getVibratorSettings() { + return vibrators.values(); + } + + /** @hide */ + public ConnectionSettings getSettingsForConnection(int connectionId){ + return connections.get(connectionId); + } + + /** @hide */ + public void setConnectionSettings(ConnectionSettings descriptor){ + connections.put(descriptor.getConnectionId(), descriptor); + } + + /** @hide */ + public Collection<ConnectionSettings> getConnectionSettings(){ + return connections.values(); + } + +} diff --git a/core/java/android/app/ProfileGroup.java b/core/java/android/app/ProfileGroup.java new file mode 100644 index 0000000..b3b70d6 --- /dev/null +++ b/core/java/android/app/ProfileGroup.java @@ -0,0 +1,348 @@ +/* + * Copyright (C) 2011 The Android Open Source 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 android.app; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.Context; +import android.media.RingtoneManager; +import android.net.Uri; +import android.os.Parcel; +import android.os.Parcelable; +import android.os.ParcelUuid; +import android.text.TextUtils; +import android.util.Log; + +import java.io.IOException; +import java.util.UUID; + +/** + * @hide + */ +public final class ProfileGroup implements Parcelable { + private static final String TAG = "ProfileGroup"; + + private String mName; + private int mNameResId; + + private UUID mUuid; + + private Uri mSoundOverride = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION); + private Uri mRingerOverride = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE); + + private Mode mSoundMode = Mode.DEFAULT; + private Mode mRingerMode = Mode.DEFAULT; + private Mode mVibrateMode = Mode.DEFAULT; + private Mode mLightsMode = Mode.DEFAULT; + + private boolean mDefaultGroup = false; + private boolean mDirty; + + /** @hide */ + public static final Parcelable.Creator<ProfileGroup> CREATOR = new Parcelable.Creator<ProfileGroup>() { + public ProfileGroup createFromParcel(Parcel in) { + return new ProfileGroup(in); + } + + @Override + public ProfileGroup[] newArray(int size) { + return new ProfileGroup[size]; + } + }; + + /** @hide */ + public ProfileGroup(UUID uuid, boolean defaultGroup) { + this(null, uuid, defaultGroup); + } + + private ProfileGroup(String name, UUID uuid, boolean defaultGroup) { + mName = name; + mUuid = (uuid != null) ? uuid : UUID.randomUUID(); + mDefaultGroup = defaultGroup; + mDirty = uuid == null; + } + + /** @hide */ + private ProfileGroup(Parcel in) { + readFromParcel(in); + } + + /** @hide */ + public boolean matches(NotificationGroup group, boolean defaultGroup) { + if (mUuid.equals(group.getUuid())) { + return true; + } + + /* fallback matches for backwards compatibility */ + boolean matches = false; + + /* fallback attempt 1: match name */ + if (mName != null && mName.equals(group.getName())) { + matches = true; + /* fallback attempt 2: match for the 'defaultGroup' flag to match the wildcard group */ + } else if (mDefaultGroup && defaultGroup) { + matches = true; + } + + if (!matches) { + return false; + } + + mName = null; + mUuid = group.getUuid(); + mDirty = true; + + return true; + } + + public UUID getUuid() { + return mUuid; + } + + public boolean isDefaultGroup() { + return mDefaultGroup; + } + + /** @hide */ + public boolean isDirty() { + return mDirty; + } + + /** @hide */ + public void setSoundOverride(Uri sound) { + mSoundOverride = sound; + mDirty = true; + } + + public Uri getSoundOverride() { + return mSoundOverride; + } + + /** @hide */ + public void setRingerOverride(Uri ringer) { + mRingerOverride = ringer; + mDirty = true; + } + + public Uri getRingerOverride() { + return mRingerOverride; + } + + /** @hide */ + public void setSoundMode(Mode soundMode) { + mSoundMode = soundMode; + mDirty = true; + } + + public Mode getSoundMode() { + return mSoundMode; + } + + /** @hide */ + public void setRingerMode(Mode ringerMode) { + mRingerMode = ringerMode; + mDirty = true; + } + + public Mode getRingerMode() { + return mRingerMode; + } + + /** @hide */ + public void setVibrateMode(Mode vibrateMode) { + mVibrateMode = vibrateMode; + mDirty = true; + } + + public Mode getVibrateMode() { + return mVibrateMode; + } + + /** @hide */ + public void setLightsMode(Mode lightsMode) { + mLightsMode = lightsMode; + mDirty = true; + } + + public Mode getLightsMode() { + return mLightsMode; + } + + // TODO : add support for LEDs / screen etc. + + /** @hide */ + public Notification processNotification(Notification notification) { + + switch (mSoundMode) { + case OVERRIDE: + notification.sound = mSoundOverride; + break; + case SUPPRESS: + silenceNotification(notification); + break; + case DEFAULT: + } + switch (mVibrateMode) { + case OVERRIDE: + notification.defaults |= Notification.DEFAULT_VIBRATE; + break; + case SUPPRESS: + suppressVibrate(notification); + break; + case DEFAULT: + } + switch (mLightsMode) { + case OVERRIDE: + notification.defaults |= Notification.DEFAULT_LIGHTS; + break; + case SUPPRESS: + suppressLights(notification); + break; + case DEFAULT: + } + return notification; + } + + private void silenceNotification(Notification notification) { + notification.defaults &= (~Notification.DEFAULT_SOUND); + notification.sound = null; + } + + private void suppressVibrate(Notification notification) { + notification.defaults &= (~Notification.DEFAULT_VIBRATE); + notification.vibrate = null; + } + + private void suppressLights(Notification notification) { + notification.defaults &= (~Notification.DEFAULT_LIGHTS); + notification.flags &= (~Notification.FLAG_SHOW_LIGHTS); + } + + /** @hide */ + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeString(mName); + new ParcelUuid(mUuid).writeToParcel(dest, 0); + dest.writeInt(mDefaultGroup ? 1 : 0); + dest.writeInt(mDirty ? 1 : 0); + dest.writeParcelable(mSoundOverride, flags); + dest.writeParcelable(mRingerOverride, flags); + + dest.writeString(mSoundMode.name()); + dest.writeString(mRingerMode.name()); + dest.writeString(mVibrateMode.name()); + dest.writeString(mLightsMode.name()); + } + + /** @hide */ + public void readFromParcel(Parcel in) { + mName = in.readString(); + mUuid = ParcelUuid.CREATOR.createFromParcel(in).getUuid(); + mDefaultGroup = in.readInt() != 0; + mDirty = in.readInt() != 0; + mSoundOverride = in.readParcelable(null); + mRingerOverride = in.readParcelable(null); + + mSoundMode = Mode.valueOf(Mode.class, in.readString()); + mRingerMode = Mode.valueOf(Mode.class, in.readString()); + mVibrateMode = Mode.valueOf(Mode.class, in.readString()); + mLightsMode = Mode.valueOf(Mode.class, in.readString()); + } + + public enum Mode { + SUPPRESS, DEFAULT, OVERRIDE; + } + + /** @hide */ + public void getXmlString(StringBuilder builder, Context context) { + builder.append("<profileGroup uuid=\""); + builder.append(TextUtils.htmlEncode(mUuid.toString())); + if (mName != null) { + builder.append("\" name=\""); + builder.append(mName); + } + builder.append("\" default=\""); + builder.append(isDefaultGroup()); + builder.append("\">\n<sound>"); + builder.append(TextUtils.htmlEncode(mSoundOverride.toString())); + builder.append("</sound>\n<ringer>"); + builder.append(TextUtils.htmlEncode(mRingerOverride.toString())); + builder.append("</ringer>\n<soundMode>"); + builder.append(mSoundMode); + builder.append("</soundMode>\n<ringerMode>"); + builder.append(mRingerMode); + builder.append("</ringerMode>\n<vibrateMode>"); + builder.append(mVibrateMode); + builder.append("</vibrateMode>\n<lightsMode>"); + builder.append(mLightsMode); + builder.append("</lightsMode>\n</profileGroup>\n"); + mDirty = false; + } + + /** @hide */ + public static ProfileGroup fromXml(XmlPullParser xpp, Context context) + throws XmlPullParserException, IOException { + String name = xpp.getAttributeValue(null, "name"); + UUID uuid = null; + String value = xpp.getAttributeValue(null, "uuid"); + + if (value != null) { + try { + uuid = UUID.fromString(value); + } catch (IllegalArgumentException e) { + Log.w(TAG, "UUID not recognized for " + name + ", using new one."); + } + } + + value = xpp.getAttributeValue(null, "default"); + boolean defaultGroup = TextUtils.equals(value, "true"); + + ProfileGroup profileGroup = new ProfileGroup(name, uuid, defaultGroup); + int event = xpp.next(); + while (event != XmlPullParser.END_TAG || !xpp.getName().equals("profileGroup")) { + if (event == XmlPullParser.START_TAG) { + name = xpp.getName(); + if (name.equals("sound")) { + profileGroup.setSoundOverride(Uri.parse(xpp.nextText())); + } else if (name.equals("ringer")) { + profileGroup.setRingerOverride(Uri.parse(xpp.nextText())); + } else if (name.equals("soundMode")) { + profileGroup.setSoundMode(Mode.valueOf(xpp.nextText())); + } else if (name.equals("ringerMode")) { + profileGroup.setRingerMode(Mode.valueOf(xpp.nextText())); + } else if (name.equals("vibrateMode")) { + profileGroup.setVibrateMode(Mode.valueOf(xpp.nextText())); + } else if (name.equals("lightsMode")) { + profileGroup.setLightsMode(Mode.valueOf(xpp.nextText())); + } + } + event = xpp.next(); + } + + /* we just loaded from XML, no need to save */ + profileGroup.mDirty = false; + + return profileGroup; + } +} diff --git a/core/java/android/app/ProfileManager.java b/core/java/android/app/ProfileManager.java new file mode 100644 index 0000000..4a0f1b7 --- /dev/null +++ b/core/java/android/app/ProfileManager.java @@ -0,0 +1,260 @@ +/* + * Copyright (C) 2011 The Android Open Source 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 android.app; + +import java.util.UUID; + +import android.content.Context; +import android.os.Handler; +import android.os.IBinder; +import android.os.ParcelUuid; +import android.os.RemoteException; +import android.os.ServiceManager; +import android.util.Log; + +/** + * @hide + */ +public class ProfileManager { + + private static IProfileManager sService; + + private Context mContext; + + private static final String TAG = "ProfileManager"; + + /** @hide */ + static public IProfileManager getService() { + if (sService != null) { + return sService; + } + IBinder b = ServiceManager.getService(Context.PROFILE_SERVICE); + sService = IProfileManager.Stub.asInterface(b); + return sService; + } + + /** @hide */ + ProfileManager(Context context, Handler handler) { + mContext = context; + } + + @Deprecated + public void setActiveProfile(String profileName) { + try { + getService().setActiveProfileByName(profileName); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + public void setActiveProfile(UUID profileUuid) { + try { + getService().setActiveProfile(new ParcelUuid(profileUuid)); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + public Profile getActiveProfile() { + try { + return getService().getActiveProfile(); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + /** @hide */ + public void addProfile(Profile profile) { + try { + getService().addProfile(profile); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + /** @hide */ + public void removeProfile(Profile profile) { + try { + getService().removeProfile(profile); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + /** @hide */ + public void updateProfile(Profile profile) { + try { + getService().updateProfile(profile); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + @Deprecated + public Profile getProfile(String profileName) { + try { + return getService().getProfileByName(profileName); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + public Profile getProfile(UUID profileUuid) { + try { + return getService().getProfile(new ParcelUuid(profileUuid)); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + public String[] getProfileNames() { + try { + Profile[] profiles = getService().getProfiles(); + String[] names = new String[profiles.length]; + for (int i = 0; i < profiles.length; i++) { + names[i] = profiles[i].getName(); + } + return names; + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + public Profile[] getProfiles() { + try { + return getService().getProfiles(); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + public boolean profileExists(String profileName) { + try { + return getService().profileExistsByName(profileName); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + // To be on the safe side, we'll return "true", to prevent duplicate profiles + // from being created. + return true; + } + } + + public boolean profileExists(UUID profileUuid) { + try { + return getService().profileExists(new ParcelUuid(profileUuid)); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + // To be on the safe side, we'll return "true", to prevent duplicate profiles + // from being created. + return true; + } + } + + public boolean notificationGroupExists(String notificationGroupName) { + try { + return getService().notificationGroupExistsByName(notificationGroupName); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + // To be on the safe side, we'll return "true", to prevent duplicate notification + // groups from being created. + return true; + } + } + + /** @hide */ + public NotificationGroup[] getNotificationGroups() { + try { + return getService().getNotificationGroups(); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + /** @hide */ + public void addNotificationGroup(NotificationGroup group) { + try { + getService().addNotificationGroup(group); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + /** @hide */ + public void removeNotificationGroup(NotificationGroup group) { + try { + getService().removeNotificationGroup(group); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + /** @hide */ + public void updateNotificationGroup(NotificationGroup group) { + try { + getService().updateNotificationGroup(group); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } + + /** @hide */ + public NotificationGroup getNotificationGroupForPackage(String pkg) { + try { + return getService().getNotificationGroupForPackage(pkg); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + /** @hide */ + public NotificationGroup getNotificationGroup(UUID uuid) { + try { + return getService().getNotificationGroup(new ParcelUuid(uuid)); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + return null; + } + + /** @hide */ + public ProfileGroup getActiveProfileGroup(String packageName) { + NotificationGroup notificationGroup = getNotificationGroupForPackage(packageName); + if(notificationGroup == null){ + ProfileGroup defaultGroup = getActiveProfile().getDefaultGroup(); + return defaultGroup; + } + return getActiveProfile().getProfileGroup(notificationGroup.getUuid()); + } + + /** @hide */ + public void resetAll() { + try { + getService().resetAll(); + } catch (RemoteException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } catch (SecurityException e) { + Log.e(TAG, e.getLocalizedMessage(), e); + } + } +} diff --git a/core/java/android/app/StreamSettings.java b/core/java/android/app/StreamSettings.java new file mode 100644 index 0000000..2f3bf27 --- /dev/null +++ b/core/java/android/app/StreamSettings.java @@ -0,0 +1,130 @@ + +package android.app; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.Context; +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.IOException; + +/** @hide */ +public final class StreamSettings implements Parcelable{ + + private int mStreamId; + private int mValue; + private boolean mOverride; + private boolean mDirty; + + /** @hide */ + public static final Parcelable.Creator<StreamSettings> CREATOR = new Parcelable.Creator<StreamSettings>() { + public StreamSettings createFromParcel(Parcel in) { + return new StreamSettings(in); + } + + @Override + public StreamSettings[] newArray(int size) { + return new StreamSettings[size]; + } + }; + + + public StreamSettings(Parcel parcel) { + readFromParcel(parcel); + } + + public StreamSettings(int streamId) { + this(streamId, 0, false); + } + + public StreamSettings(int streamId, int value, boolean override) { + mStreamId = streamId; + mValue = value; + mOverride = override; + mDirty = false; + } + + public int getStreamId() { + return mStreamId; + } + + public int getValue() { + return mValue; + } + + public void setValue(int value) { + mValue = value; + mDirty = true; + } + + public void setOverride(boolean override) { + mOverride = override; + mDirty = true; + } + + public boolean isOverride() { + return mOverride; + } + + /** @hide */ + public boolean isDirty() { + return mDirty; + } + + /** @hide */ + public static StreamSettings fromXml(XmlPullParser xpp, Context context) + throws XmlPullParserException, IOException { + int event = xpp.next(); + StreamSettings streamDescriptor = new StreamSettings(0); + while (event != XmlPullParser.END_TAG || !xpp.getName().equals("streamDescriptor")) { + if (event == XmlPullParser.START_TAG) { + String name = xpp.getName(); + if (name.equals("streamId")) { + streamDescriptor.mStreamId = Integer.parseInt(xpp.nextText()); + } else if (name.equals("value")) { + streamDescriptor.mValue = Integer.parseInt(xpp.nextText()); + } else if (name.equals("override")) { + streamDescriptor.mOverride = Boolean.parseBoolean(xpp.nextText()); + } + } + event = xpp.next(); + } + return streamDescriptor; + } + + /** @hide */ + public void getXmlString(StringBuilder builder, Context context) { + builder.append("<streamDescriptor>\n<streamId>"); + builder.append(mStreamId); + builder.append("</streamId>\n<value>"); + builder.append(mValue); + builder.append("</value>\n<override>"); + builder.append(mOverride); + builder.append("</override>\n</streamDescriptor>\n"); + mDirty = false; + } + + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mStreamId); + dest.writeInt(mOverride ? 1 : 0); + dest.writeInt(mValue); + dest.writeInt(mDirty ? 1 : 0); + } + + /** @hide */ + public void readFromParcel(Parcel in) { + mStreamId = in.readInt(); + mOverride = in.readInt() != 0; + mValue = in.readInt(); + mDirty = in.readInt() != 0; + } +} diff --git a/core/java/android/app/VibratorSettings.java b/core/java/android/app/VibratorSettings.java new file mode 100644 index 0000000..10e5ca2 --- /dev/null +++ b/core/java/android/app/VibratorSettings.java @@ -0,0 +1,150 @@ + +package android.app; + +import org.xmlpull.v1.XmlPullParser; +import org.xmlpull.v1.XmlPullParserException; + +import android.content.Context; +import android.media.AudioManager; +import android.os.Parcel; +import android.os.Parcelable; + +import java.io.IOException; + +/** @hide */ +public final class VibratorSettings implements Parcelable{ + + public static final int OFF = 0; + public static final int SILENT = 1; + public static final int ON = 2; + + private int mVibratorId; + private int mValue; + private boolean mOverride; + private boolean mDirty; + + /** @hide */ + public static final Parcelable.Creator<VibratorSettings> CREATOR = new Parcelable.Creator<VibratorSettings>() { + public VibratorSettings createFromParcel(Parcel in) { + return new VibratorSettings(in); + } + + @Override + public VibratorSettings[] newArray(int size) { + return new VibratorSettings[size]; + } + }; + + + public VibratorSettings(Parcel parcel) { + readFromParcel(parcel); + } + + public VibratorSettings(int vibratorId) { + this(vibratorId, 0, false); + } + + public VibratorSettings(int vibratorId, int value, boolean override) { + mVibratorId = vibratorId; + mValue = value; + mOverride = override; + mDirty = false; + } + + public int getVibratorId() { + return mVibratorId; + } + + public int getValue() { + return mValue; + } + + public void setValue(int value) { + mValue = value; + mDirty = true; + } + + public void setOverride(boolean override) { + mOverride = override; + mDirty = true; + } + + public boolean isOverride() { + return mOverride; + } + + /** @hide */ + public boolean isDirty() { + return mDirty; + } + + /** @hide */ + public static VibratorSettings fromXml(XmlPullParser xpp, Context context) + throws XmlPullParserException, IOException { + int event = xpp.next(); + VibratorSettings vibratorDescriptor = new VibratorSettings(0); + while (event != XmlPullParser.END_TAG || !xpp.getName().equals("vibratorDescriptor")) { + if (event == XmlPullParser.START_TAG) { + String name = xpp.getName(); + if (name.equals("vibratorId")) { + vibratorDescriptor.mVibratorId = Integer.parseInt(xpp.nextText()); + } else if (name.equals("value")) { + vibratorDescriptor.mValue = Integer.parseInt(xpp.nextText()); + } else if (name.equals("override")) { + vibratorDescriptor.mOverride = Boolean.parseBoolean(xpp.nextText()); + } + } + event = xpp.next(); + } + return vibratorDescriptor; + } + + /** @hide */ + public void getXmlString(StringBuilder builder, Context context) { + builder.append("<vibratorDescriptor>\n<vibratorId>"); + builder.append(mVibratorId); + builder.append("</vibratorId>\n<value>"); + builder.append(mValue); + builder.append("</value>\n<override>"); + builder.append(mOverride); + builder.append("</override>\n</vibratorDescriptor>\n"); + mDirty = false; + } + + @Override + public int describeContents() { + return 0; + } + + /** @hide */ + @Override + public void writeToParcel(Parcel dest, int flags) { + dest.writeInt(mVibratorId); + dest.writeInt(mOverride ? 1 : 0); + dest.writeInt(mValue); + dest.writeInt(mDirty ? 1 : 0); + } + + /** @hide */ + public void readFromParcel(Parcel in) { + mVibratorId = in.readInt(); + mOverride = in.readInt() != 0; + mValue = in.readInt(); + mDirty = in.readInt() != 0; + } + + /** @hide */ + public void processOverride(Context context) { + AudioManager amgr = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); + switch (mValue) { + case OFF: + amgr.setVibrateSetting(mVibratorId, AudioManager.VIBRATE_SETTING_OFF); + break; + case SILENT: + amgr.setVibrateSetting(mVibratorId, AudioManager.VIBRATE_SETTING_ONLY_SILENT); + default: + amgr.setVibrateSetting(mVibratorId, AudioManager.VIBRATE_SETTING_ON); + break; + } + } +} diff --git a/core/java/android/content/Context.java b/core/java/android/content/Context.java index 7aa2507..f0c6ce8 100644 --- a/core/java/android/content/Context.java +++ b/core/java/android/content/Context.java @@ -1890,6 +1890,18 @@ public abstract class Context { /** * Use with {@link #getSystemService} to retrieve a + * {@link android.app.ProfileManager} for setting + * notification profiles. + * + * @see #getSystemService + * @see android.app.ProfileManager + * + * @hide + */ + public static final String PROFILE_SERVICE = "profile"; + + /** + * Use with {@link #getSystemService} to retrieve a * {@link android.view.accessibility.AccessibilityManager} for giving the user * feedback for UI events through the registered event listeners. * diff --git a/core/java/android/net/wimax/WimaxHelper.java b/core/java/android/net/wimax/WimaxHelper.java new file mode 100644 index 0000000..f6c7a40 --- /dev/null +++ b/core/java/android/net/wimax/WimaxHelper.java @@ -0,0 +1,188 @@ +/* + * Copyright (C) 2011 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 android.net.wimax; + +import dalvik.system.DexClassLoader; + +import android.content.Context; +import android.content.ContextWrapper; +import android.os.Handler; +import android.os.IBinder; +import android.os.ServiceManager; +import android.util.Log; +import android.provider.Settings; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; + +/** + * {@hide} + */ +public class WimaxHelper { + + private static final String TAG = "WimaxHelper"; + + private static final String WIMAX_CONTROLLER_CLASSNAME = "com.htc.net.wimax.WimaxController"; + private static final String WIMAX_MANAGER_CLASSNAME = "android.net.fourG.wimax.Wimax4GManager"; + + private static DexClassLoader sWimaxClassLoader; + private static String sWimaxManagerClassname, sIsWimaxEnabledMethodname, + sSetWimaxEnabledMethodname, sGetWimaxStateMethodname; + + public static boolean isWimaxSupported(Context context) { + return context.getResources().getBoolean( + com.android.internal.R.bool.config_wimaxEnabled); + } + + public static DexClassLoader getWimaxClassLoader(Context context) { + if (isWimaxSupported(context)) { + if (sWimaxClassLoader == null) { + sWimaxManagerClassname = context.getResources().getString( + com.android.internal.R.string.config_wimaxManagerClassname); + + // WimaxController::getWimaxState == Wimax4GManager::get4GState. + // However, Wimax4GManager also implements a different getWimaxState + // method, which returns a WimaxState object describing the connection + // state, not the enabled state. Other methods are similarly renamed. + if (sWimaxManagerClassname.equals(WIMAX_CONTROLLER_CLASSNAME)) { + sIsWimaxEnabledMethodname = "isWimaxEnabled"; + sSetWimaxEnabledMethodname = "setWimaxEnabled"; + sGetWimaxStateMethodname = "getWimaxState"; + } else if (sWimaxManagerClassname.equals(WIMAX_MANAGER_CLASSNAME)) { + sIsWimaxEnabledMethodname = "is4GEnabled"; + sSetWimaxEnabledMethodname = "set4GEnabled"; + sGetWimaxStateMethodname = "get4GState"; + } + + String wimaxJarLocation = context.getResources().getString( + com.android.internal.R.string.config_wimaxServiceJarLocation); + String wimaxLibLocation = context.getResources().getString( + com.android.internal.R.string.config_wimaxNativeLibLocation); + sWimaxClassLoader = new DexClassLoader(wimaxJarLocation, + new ContextWrapper(context).getCacheDir().getAbsolutePath(), + wimaxLibLocation,ClassLoader.getSystemClassLoader()); + } + return sWimaxClassLoader; + } + return null; + } + + public static Object createWimaxService(Context context, Handler handler) { + Object controller = null; + + try { + DexClassLoader wimaxClassLoader = getWimaxClassLoader(context); + if (sWimaxManagerClassname.equals(WIMAX_CONTROLLER_CLASSNAME)) { + // Load supersonic's and speedy's WimaxController. + IBinder b = ServiceManager.getService(WimaxManagerConstants.WIMAX_SERVICE); + if (b != null) { + Class<?> klass = wimaxClassLoader.loadClass("com.htc.net.wimax.IWimaxController$Stub"); + if (klass != null) { + Method asInterface = klass.getMethod("asInterface", IBinder.class); + Object wc = asInterface.invoke(null, b); + if (wc != null) { + klass = wimaxClassLoader.loadClass(WIMAX_CONTROLLER_CLASSNAME); + if (klass != null) { + Constructor<?> ctor = klass.getDeclaredConstructors()[1]; + controller = ctor.newInstance(wc, handler); + } + } + } + } + } else if (sWimaxManagerClassname.equals(WIMAX_MANAGER_CLASSNAME)) { + // Load crespo4g's (and epicmtd's) Wimax4GManager. + // Note that crespo4g's implementation grabs WIMAX_SERVICE internally, so + // it doesn't need to be passed in. Other implementations (may) require + // WIMAX_SERVICE to be grabbed externally, so check Wimax4GManager::<init>. + Class<?> klass = wimaxClassLoader.loadClass(WIMAX_MANAGER_CLASSNAME); + if (klass != null) { + Constructor<?> ctor = klass.getDeclaredConstructors()[0]; + controller = ctor.newInstance(); + } + } + } catch (Exception e) { + Log.e(TAG, "Unable to create WimaxController instance", e); + } + + return controller; + } + + public static boolean isWimaxEnabled(Context context) { + boolean ret = false; + try { + Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE); + Method m = wimaxService.getClass().getMethod(sIsWimaxEnabledMethodname); + ret = (Boolean) m.invoke(wimaxService); + } catch (Exception e) { + Log.e(TAG, "Unable to get WiMAX enabled state!", e); + } + return ret; + } + + public static boolean setWimaxEnabled(Context context, boolean enabled) { + boolean ret = false; + try { + Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE); + Method m = wimaxService.getClass().getMethod(sSetWimaxEnabledMethodname, boolean.class); + ret = (Boolean) m.invoke(wimaxService, enabled); + if (ret) + Settings.Secure.putInt(context.getContentResolver(), + Settings.Secure.WIMAX_ON, (Boolean) enabled ? 1 : 0); + } catch (Exception e) { + Log.e(TAG, "Unable to set WiMAX state!", e); + } + return ret; + } + + public static int getWimaxState(Context context) { + int ret = 0; + try { + Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE); + Method m = wimaxService.getClass().getMethod(sGetWimaxStateMethodname); + ret = (Integer) m.invoke(wimaxService); + } catch (Exception e) { + Log.e(TAG, "Unable to get WiMAX state!", e); + } + return ret; + } + + public static boolean wimaxRescan(Context context) { + boolean ret = false; + try { + Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE); + Method wimaxRescan = wimaxService.getClass().getMethod("wimaxRescan"); + if (wimaxRescan != null) { + wimaxRescan.invoke(wimaxService); + ret = true; + } + } catch (Exception e) { + Log.e(TAG, "Unable to perform WiMAX rescan!", e); + } + return ret; + } + + private static Object getWimaxInfo(Context context) { + Object wimaxInfo = null; + try { + Object wimaxService = context.getSystemService(WimaxManagerConstants.WIMAX_SERVICE); + Method getConnectionInfo = wimaxService.getClass().getMethod("getConnectionInfo"); + wimaxInfo = getConnectionInfo.invoke(wimaxService); + } catch (Exception e) { + Log.e(TAG, "Unable to get a WimaxInfo object!", e); + } + return wimaxInfo; + } +} diff --git a/core/java/android/net/wimax/WimaxManagerConstants.java b/core/java/android/net/wimax/WimaxManagerConstants.java index b4aaf5b..a8239ba 100644 --- a/core/java/android/net/wimax/WimaxManagerConstants.java +++ b/core/java/android/net/wimax/WimaxManagerConstants.java @@ -67,11 +67,21 @@ public class WimaxManagerConstants public static final int NET_4G_STATE_DISABLED = 1; /** + * Indicatates Wimax is disabling. + */ + public static final int NET_4G_STATE_DISABLING = 0; + + /** * Indicatates Wimax is enabled. */ public static final int NET_4G_STATE_ENABLED = 3; /** + * Indicatates Wimax is enabling. + */ + public static final int NET_4G_STATE_ENABLING = 2; + + /** * Indicatates Wimax status is known. */ public static final int NET_4G_STATE_UNKNOWN = 4; @@ -101,4 +111,9 @@ public class WimaxManagerConstants */ public static final int WIMAX_STATE_DISCONNECTED = 9; + /** + * Constants for HTC/SQN WiMAX implementation + */ + public static final String WIMAX_ENABLED_CHANGED_ACTION = "com.htc.net.wimax.WIMAX_ENABLED_CHANGED"; + public static final String CURRENT_WIMAX_ENABLED_STATE = "curWimaxEnabledState"; } diff --git a/core/java/android/preference/ListPreferenceMultiSelect.java b/core/java/android/preference/ListPreferenceMultiSelect.java new file mode 100644 index 0000000..83edc72 --- /dev/null +++ b/core/java/android/preference/ListPreferenceMultiSelect.java @@ -0,0 +1,112 @@ +/* + * Copyright (C) 2012 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 android.preference; + +import android.app.AlertDialog.Builder; +import android.content.Context; +import android.content.DialogInterface; +import android.text.TextUtils; +import android.util.AttributeSet; + +/** + * This Preference type is required for the Power Widget functionality. It should + * not be used for any other multi select lists, use the Android MultiselectListPreference + * instead + * @hide + */ +public class ListPreferenceMultiSelect extends ListPreference { + + private static final String SEPARATOR = "OV=I=XseparatorX=I=VO"; + + private boolean[] mClickedDialogEntryIndices; + + public ListPreferenceMultiSelect(Context context) { + super(context); + } + + public ListPreferenceMultiSelect(Context context, AttributeSet attrs) { + super(context, attrs); + } + + @Override + protected void onPrepareDialogBuilder(Builder builder) { + CharSequence[] entries = getEntries(); + CharSequence[] entryValues = getEntryValues(); + + if (entries == null || entryValues == null || entries.length != entryValues.length) { + throw new IllegalStateException( + this.getClass().getSimpleName() + + " requires an entries array and an entryValues array which are both the same length"); + } + + mClickedDialogEntryIndices = new boolean[entryValues.length]; + restoreCheckedEntries(); + builder.setMultiChoiceItems(entries, mClickedDialogEntryIndices, new DialogInterface.OnMultiChoiceClickListener() { + @Override + public void onClick(DialogInterface dialog, int which, boolean isChecked) { + mClickedDialogEntryIndices[which] = isChecked; + } + }); + } + + public static String[] parseStoredValue(CharSequence val) { + if (TextUtils.isEmpty(val)) { + return null; + } else { + return val.toString().split(SEPARATOR); + } + } + + private void restoreCheckedEntries() { + CharSequence[] entryValues = getEntryValues(); + + String[] vals = parseStoredValue(getValue()); + if (vals != null) { + for (String val : vals) { + for (int i = 0; i < entryValues.length; i++) { + CharSequence entry = entryValues[i]; + if (entry.equals(val)) { + mClickedDialogEntryIndices[i] = true; + break; + } + } + } + } + } + + @Override + protected void onDialogClosed(boolean positiveResult) { + CharSequence[] entryValues = getEntryValues(); + + if (positiveResult && entryValues != null) { + StringBuilder value = new StringBuilder(); + for (int i = 0; i < entryValues.length; i++) { + if (mClickedDialogEntryIndices[i]) { + if (value.length() > 0) { + value.append(SEPARATOR); + } + value.append(entryValues[i]); + } + } + + String val = value.toString(); + if (callChangeListener(val)) { + setValue(val); + } + } + } +} diff --git a/core/java/android/preference/VolumePreference.java b/core/java/android/preference/VolumePreference.java index caf55d7..b763022 100644 --- a/core/java/android/preference/VolumePreference.java +++ b/core/java/android/preference/VolumePreference.java @@ -146,6 +146,11 @@ public class VolumePreference extends SeekBarDialogPreference implements } } + /** @hide */ + protected boolean onVolumeChange(SeekBarVolumizer volumizer, int value) { + return true; + } + @Override protected Parcelable onSaveInstanceState() { final Parcelable superState = super.onSaveInstanceState(); @@ -305,10 +310,14 @@ public class VolumePreference extends SeekBarDialogPreference implements } void postSetVolume(int progress) { - // Do the volume changing separately to give responsive UI - mLastProgress = progress; - mHandler.removeCallbacks(this); - mHandler.post(this); + if (onVolumeChange(this, progress)) { + // Do the volume changing separately to give responsive UI + mLastProgress = progress; + mHandler.removeCallbacks(this); + mHandler.post(this); + } else { + mSeekBar.setProgress(mLastProgress); + } } public void onStartTrackingTouch(SeekBar seekBar) { diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java index 2a3f916..99db53c 100644 --- a/core/java/android/provider/Settings.java +++ b/core/java/android/provider/Settings.java @@ -1688,6 +1688,148 @@ public final class Settings { public static final int SCREEN_BRIGHTNESS_MODE_AUTOMATIC = 1; /** + * Indicates that custom light sensor settings has changed. + * The value is random and changes reloads light settings. + * + * @hide + */ + public static final String LIGHTS_CHANGED = "lights_changed"; + + /** + * Whether custom light sensor levels & values are enabled. The value is + * boolean (1 or 0). + * + * @hide + */ + public static final String LIGHT_SENSOR_CUSTOM = "light_sensor_custom"; + + /** + * Screen dim value to use if LIGHT_SENSOR_CUSTOM is set. The value is int. + * Default is android.os.BRIGHTNESS_DIM. + * + * @hide + */ + public static final String LIGHT_SCREEN_DIM = "light_screen_dim"; + + /** + * Custom light sensor levels. The value is a comma separated int array + * with length N. + * Example: "100,300,3000". + * + * @hide + */ + public static final String LIGHT_SENSOR_LEVELS = "light_sensor_levels"; + + /** + * Custom light sensor lcd values. The value is a comma separated int array + * with length N+1. + * Example: "10,50,100,255". + * + * @hide + */ + public static final String LIGHT_SENSOR_LCD_VALUES = "light_sensor_lcd_values"; + + /** + * Custom light sensor lcd values. The value is a comma separated int array + * with length N+1. + * Example: "10,50,100,255". + * + * @hide + */ + public static final String LIGHT_SENSOR_BUTTON_VALUES = "light_sensor_button_values"; + + /** + * Custom light sensor lcd values. The value is a comma separated int array + * with length N+1. + * Example: "10,50,100,255". + * + * @hide + */ + public static final String LIGHT_SENSOR_KEYBOARD_VALUES = "light_sensor_keyboard_values"; + + /** + * Whether light sensor is allowed to decrease when calculating automatic + * backlight. The value is boolean (1 or 0). + * + * @hide + */ + public static final String LIGHT_DECREASE = "light_decrease"; + + /** + * Light sensor hysteresis for decreasing backlight. The value is + * int (0-99) representing % (0-0.99 as float). Example: + * + * Levels Output + * 0 - 100 50 + * 100 - 200 100 + * 200 - Inf 255 + * + * Current sensor value is 150 which gives light value 100. Hysteresis is 50. + * Current level lower bound is 100 and previous lower bound is 0. + * Sensor value must drop below 100-(100-0)*(50/100)=50 for output to become 50 + * (corresponding to the 0 - 100 level). + * @hide + */ + public static final String LIGHT_HYSTERESIS = "light_hysteresis"; + + /** + * Whether light sensor used when calculating automatic backlight should + * be filtered through an moving average filter. + * The value is boolean (1 or 0). + * + * @hide + */ + public static final String LIGHT_FILTER = "light_filter"; + + /** + * Window length of filter used when calculating automatic backlight. + * One minute means that the average sensor value last minute is used. + * The value is integer (milliseconds) + * + * @hide + */ + public static final String LIGHT_FILTER_WINDOW = "light_filter_window"; + + /** + * Reset threshold of filter used when calculating automatic backlight. + * Sudden large jumps in sensor value resets the filter. This is used + * to make the filter respond quickly to large enough changes in input + * while still filtering small changes. Example: + * + * Current filter value (average) is 100 and sensor value is changing to + * 10, 150, 100, 30, 50. The filter is continously taking the average of + * the samples. Now the user goes outside and the value jumps over 1000. + * The difference between current average and new sample is larger than + * the reset threshold and filter is reset. It begins calculating a new + * average on samples around 1000 (say, 800, 1200, 1000, 1100 etc.) + * + * The value is integer (lux) + * + * @hide + */ + public static final String LIGHT_FILTER_RESET = "light_filter_reset"; + + /** + * Sample interval of filter used when calculating automatic backlight. + * The value is integer (milliseconds) + * + * @hide + */ + public static final String LIGHT_FILTER_INTERVAL = "light_filter_interval"; + + /** + * Whether to enable the electron beam animation when turning screen on + * + * @hide */ + public static final String ELECTRON_BEAM_ANIMATION_ON = "electron_beam_animation_on"; + + /** + * Whether to enable the electron beam animation when turning screen off + * + * @hide */ + public static final String ELECTRON_BEAM_ANIMATION_OFF = "electron_beam_animation_off"; + + /** * Control whether the process CPU usage meter should be shown. * * @deprecated Use {@link Global#SHOW_PROCESSES} instead @@ -1706,6 +1848,22 @@ public final class Settings { public static final String ALWAYS_FINISH_ACTIVITIES = Global.ALWAYS_FINISH_ACTIVITIES; /** + * Volume Overlay Mode, This is behaviour of the volume overlay panel + * Defaults to 0 - which is simple + * @hide + */ + public static final String MODE_VOLUME_OVERLAY = "mode_volume_overlay"; + + /** @hide */ + public static final int VOLUME_OVERLAY_SINGLE = 0; + /** @hide */ + public static final int VOLUME_OVERLAY_EXPANDABLE = 1; + /** @hide */ + public static final int VOLUME_OVERLAY_EXPANDED = 2; + /** @hide */ + public static final int VOLUME_OVERLAY_NONE = 3; + + /** * Determines which streams are affected by ringer mode changes. The * stream type's bit should be set to 1 if it should be muted when going * into an inaudible ringer mode. @@ -1782,6 +1940,12 @@ public final class Settings { public static final String VOLUME_BLUETOOTH_SCO = "volume_bluetooth_sco"; /** + * Whether to prevent loud volume levels when headset is first plugged in. + * @hide + */ + public static final String SAFE_HEADSET_VOLUME_RESTORE = "safe_headset_volume_restore"; + + /** * Master volume (float in the range 0.0f to 1.0f). * @hide */ @@ -1813,6 +1977,24 @@ public final class Settings { "notifications_use_ring_volume"; /** + * Whether the phone ringtone should be played in an increasing manner + * @hide + */ + public static final String INCREASING_RING = "increasing_ring"; + + /** + * Minimum volume index for increasing ring volume + * @hide + */ + public static final String INCREASING_RING_MIN_VOLUME = "increasing_ring_min_vol"; + + /** + * Time (in ms) between ringtone volume increases + * @hide + */ + public static final String INCREASING_RING_INTERVAL = "increasing_ring_interval"; + + /** * Whether silent mode should allow vibration feedback. This is used * internally in AudioService and the Sound settings activity to * coordinate decoupling of vibrate and silent modes. This setting @@ -2008,6 +2190,19 @@ public final class Settings { public static final String ACCELEROMETER_ROTATION = "accelerometer_rotation"; /** + * Control the type of rotation which can be performed using the accelerometer + * if ACCELEROMETER_ROTATION is enabled. + * Value is a bitwise combination of + * 1 = 0 degrees (portrait) + * 2 = 90 degrees (left) + * 4 = 180 degrees (inverted portrait) + * 8 = 270 degrees (right) + * Setting to 0 is effectively orientation lock + * @hide + */ + public static final String ACCELEROMETER_ROTATION_ANGLES = "accelerometer_rotation_angles"; + + /** * Default screen rotation when no other policy applies. * When {@link #ACCELEROMETER_ROTATION} is zero and no on-screen Activity expresses a * preference, this rotation value will be used. Must be one of the @@ -2079,6 +2274,13 @@ public final class Settings { public static final String TTY_MODE = "tty_mode"; /** + * Whether noise suppression is enabled. The value is + * boolean (1 or 0). + * @hide + */ + public static final String NOISE_SUPPRESSION = "noise_suppression"; + + /** * Whether the sounds effects (key clicks, lid open ...) are enabled. The value is * boolean (1 or 0). */ @@ -2105,6 +2307,109 @@ public final class Settings { public static final String NOTIFICATION_LIGHT_PULSE = "notification_light_pulse"; /** + * What color to use for the notification LED by default + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR = "notification_light_pulse_default_color"; + + /** + * How long to flash the notification LED by default + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON = "notification_light_pulse_default_led_on"; + + /** + * How long to wait between flashes for the notification LED by default + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF = "notification_light_pulse_default_led_off"; + + /** + * What color to use for the missed call notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CALL_COLOR = "notification_light_pulse_call_color"; + + /** + * How long to flash the missed call notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CALL_LED_ON = "notification_light_pulse_call_led_on"; + + /** + * How long to wait between flashes for the missed call notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CALL_LED_OFF = "notification_light_pulse_call_led_off"; + + /** + * What color to use for the voicemail notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_COLOR = "notification_light_pulse_vmail_color"; + + /** + * How long to flash the voicemail notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_LED_ON = "notification_light_pulse_vmail_led_on"; + + /** + * How long to wait between flashes for the voicemail notification LED + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_VMAIL_LED_OFF = "notification_light_pulse_vmail_led_off"; + + /** + * Whether to use the custom LED values for the notification pulse LED. + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CUSTOM_ENABLE = "notification_light_pulse_custom_enable"; + + /** + * Which custom LED values to use for the notification pulse LED. + * @hide + */ + public static final String NOTIFICATION_LIGHT_PULSE_CUSTOM_VALUES = "notification_light_pulse_custom_values"; + + /** + * Whether the battery light should be enabled (if hardware supports it) + * The value is boolean (1 or 0). + * @hide + */ + public static final String BATTERY_LIGHT_ENABLED = "battery_light_enabled"; + + /** + * Whether the battery LED should repeatedly flash when the battery is low + * on charge. The value is boolean (1 or 0). + * @hide + */ + public static final String BATTERY_LIGHT_PULSE = "battery_light_pulse"; + + /** + * What color to use for the battery LED while charging - low + * @hide + */ + public static final String BATTERY_LIGHT_LOW_COLOR = "battery_light_low_color"; + + /** + * What color to use for the battery LED while charging - medium + * @hide + */ + public static final String BATTERY_LIGHT_MEDIUM_COLOR = "battery_light_medium_color"; + + /** + * What color to use for the battery LED while charging - full + * @hide + */ + public static final String BATTERY_LIGHT_FULL_COLOR = "battery_light_full_color"; + + /** Sprint MWI Quirk: Show message wait indicator notifications + * @hide + */ + public static final String ENABLE_MWI_NOTIFICATION = "enable_mwi_notification"; + + /** * Show pointer location on screen? * 0 = no * 1 = yes @@ -2265,6 +2570,362 @@ public final class Settings { public static final String POINTER_SPEED = "pointer_speed"; /** + * Use the Notification Power Widget? (Who wouldn't!) + * + * @hide + */ + public static final String EXPANDED_VIEW_WIDGET = "expanded_view_widget"; + + /** + * Whether to hide the notification screen after clicking on a widget + * button + * + * @hide + */ + public static final String EXPANDED_HIDE_ONCHANGE = "expanded_hide_onchange"; + + /** + * Hide scroll bar in power widget + * + * @hide + */ + public static final String EXPANDED_HIDE_SCROLLBAR = "expanded_hide_scrollbar"; + + /** + * Hide indicator in status bar widget + * + * @hide + */ + public static final String EXPANDED_HIDE_INDICATOR = "expanded_hide_indicator"; + + /** + * Haptic feedback in power widget + * + * @hide + */ + public static final String EXPANDED_HAPTIC_FEEDBACK = "expanded_haptic_feedback"; + + /** + * Notification Indicator Color + * + * @hide + */ + public static final String EXPANDED_VIEW_WIDGET_COLOR = "expanded_widget_color"; + + /** + * Widget Buttons to Use + * + * @hide + */ + public static final String WIDGET_BUTTONS = "expanded_widget_buttons"; + + /** + * Widget Buttons to Use - Tablet + * + * @hide + */ + public static final String WIDGET_BUTTONS_TABLET = "expanded_widget_buttons_tablet"; + + /** + * Navigation controls to Use + * + * @hide + */ + public static final String NAV_BUTTONS = "nav_buttons"; + + /** + * Notification Power Widget - Custom Brightness Mode + * @hide + */ + public static final String EXPANDED_BRIGHTNESS_MODE = "expanded_brightness_mode"; + + /** + * Notification Power Widget - Custom Network Mode + * @hide + */ + public static final String EXPANDED_NETWORK_MODE = "expanded_network_mode"; + + /** + * Notification Power Widget - Custom LTE Toggle + * 1 - lte on, 0 - lte off + * @hide + */ + public static final String LTE_MODE = "lte_mode"; + + /** + * Notification Power Widget - Custom Screen Timeout + * @hide + */ + public static final String EXPANDED_SCREENTIMEOUT_MODE = "expanded_screentimeout_mode"; + + /** + * Notification Power Widget - Custom Ring Mode + * @hide + */ + public static final String EXPANDED_RING_MODE = "expanded_ring_mode"; + + /** + * Notification Power Widget - Custom Torch Mode + * @hide + */ + public static final String EXPANDED_FLASH_MODE = "expanded_flash_mode"; + + /** + * AutoHide CombinedBar on tablets. + * @hide + */ + public static final String COMBINED_BAR_AUTO_HIDE = "combined_bar_auto_hide"; + + /** + * Display style of AM/PM next to clock in status bar + * 0: Normal display (Eclair stock) + * 1: Small display (Froyo stock) + * 2: No display (Gingerbread/ICS stock) + * default: 2 + * @hide + */ + public static final String STATUS_BAR_AM_PM = "status_bar_am_pm"; + + /** + * Display style of the status bar battery information + * 0: Display the stock battery information + * 1: Display cm battery percentage implementation / dont show stock icon + * 2: Hide the battery information + * default: 0 + * @hide + */ + public static final String STATUS_BAR_BATTERY = "status_bar_battery"; + + /** + * Whether to show the clock in status bar + * of the stock battery icon + * 0: don't show the clock + * 1: show the clock + * default: 1 + * @hide + */ + public static final String STATUS_BAR_CLOCK = "status_bar_clock"; + + /** + * Whether to show the signal text or signal bars. + * default: 0 + * 0: show signal bars + * 1: show signal text numbers + * 2: show signal text numbers w/small dBm appended + * @hide + */ + public static final String STATUS_BAR_SIGNAL_TEXT = "status_bar_signal"; + + /** + * Whether to control brightness from status bar + * + * @hide + */ + public static final String STATUS_BAR_BRIGHTNESS_CONTROL = "status_bar_brightness_control"; + + /** + * Whether to show the IME switcher in the status bar + * @hide + */ + public static final String STATUS_BAR_IME_SWITCHER = "status_bar_ime_switcher"; + + /** + * Whether to use a separate delay for "slide to unlock" and security + * lock + * @hide + */ + public static final String SCREEN_LOCK_SLIDE_DELAY_TOGGLE = "screen_lock_slide_delay_toggle"; + + /** + * How many ms to delay before enabling the "slide to unlock" screen + * lock when the screen goes off due to timeout + * @hide + */ + public static final String SCREEN_LOCK_SLIDE_TIMEOUT_DELAY = "screen_lock_slide_timeout_delay"; + + /** + * How many ms to delay before enabling the "slide to unlock" screen + * lock when the screen is turned off by the user + * @hide + */ + public static final String SCREEN_LOCK_SLIDE_SCREENOFF_DELAY = "screen_lock_slide_screenoff_delay"; + + /** + * Whether to use the custom quick unlock screen control + * @hide + */ + public static final String LOCKSCREEN_QUICK_UNLOCK_CONTROL = "lockscreen_quick_unlock_control"; + + /** + * Boolean value whether to link ringtone and notification volumes + * + * @hide + */ + public static final String VOLUME_LINK_NOTIFICATION = "volume_link_notification"; + + /** + * Whether to unlock the menu key. The value is boolean (1 or 0). + * @hide + */ + public static final String MENU_UNLOCK_SCREEN = "menu_unlock_screen"; + + /** + * Whether to wake the screen with the volume keys, the value is boolean. + * @hide + */ + public static final String VOLUME_WAKE_SCREEN = "volume_wake_screen"; + + /** + * Whether or not volume button music controls should be enabled to seek media tracks + * @hide + */ + public static final String VOLBTN_MUSIC_CONTROLS = "volbtn_music_controls"; + + /** + * Whether national data roaming should be used. + * @hide + */ + public static final String MVNO_ROAMING = "mvno_roaming"; + + /** + * Whether to enable quiet hours. + * @hide + */ + public static final String QUIET_HOURS_ENABLED = "quiet_hours_enabled"; + + /** + * Sets when quiet hours starts. This is stored in minutes from the start of the day. + * @hide + */ + public static final String QUIET_HOURS_START = "quiet_hours_start"; + + /** + * Sets when quiet hours end. This is stored in minutes from the start of the day. + * @hide + */ + public static final String QUIET_HOURS_END = "quiet_hours_end"; + + /** + * Whether to remove the sound from outgoing notifications during quiet hours. + * @hide + */ + public static final String QUIET_HOURS_MUTE = "quiet_hours_mute"; + + /** + * Whether to disable haptic feedback during quiet hours. + * @hide + */ + public static final String QUIET_HOURS_HAPTIC = "quiet_hours_haptic"; + + /** + * Whether to remove the vibration from outgoing notifications during quiet hours. + * @hide + */ + public static final String QUIET_HOURS_STILL = "quiet_hours_still"; + + /** + * Whether to attempt to dim the LED color during quiet hours. + * @hide + */ + public static final String QUIET_HOURS_DIM = "quiet_hours_dim"; + + /** + * Sets the lockscreen background style + * @hide + */ + public static final String LOCKSCREEN_BACKGROUND = "lockscreen_background"; + + /** + * Show the weather on the lock screen + * @hide + */ + public static final String LOCKSCREEN_WEATHER = "lockscreen_weather"; + + /** + * Show the current weather location on the lock screen + * @hide + */ + public static final String WEATHER_SHOW_LOCATION = "weather_show_location"; + + /** + * Show the current weather location on the lock screen + * @hide + */ + public static final String WEATHER_SHOW_TIMESTAMP = "weather_show_timestamp"; + + /** + * Use the custom/manually configured weather location + * @hide + */ + public static final String WEATHER_USE_CUSTOM_LOCATION = "weather_use_custom_location"; + + /** + * Stores the custom/manually configured weather location + * @hide + */ + public static final String WEATHER_CUSTOM_LOCATION = "weather_custom_location"; + + /** + * Stores the weather update frequency + * @hide + */ + public static final String WEATHER_UPDATE_INTERVAL = "weather_update_interval"; + + /** + * Use Metric measurements (celcius, km/h) for weather data + * @hide + */ + public static final String WEATHER_USE_METRIC = "weather_use_metric"; + + /** + * Invert low/high temperature display + * @hide + */ + public static final String WEATHER_INVERT_LOWHIGH = "weather_invert_lowhigh"; + + /** + * Whether to show the next calendar event + * @hide + */ + public static final String LOCKSCREEN_CALENDAR = "lockscreen_calendar"; + + /** + * Whether to show the next calendar event's location + * @hide + */ + public static final String LOCKSCREEN_CALENDAR_SHOW_LOCATION = "lockscreen_calendar_show_location"; + + /** + * Whether to show the next calendar event's description + * @hide + */ + public static final String LOCKSCREEN_CALENDAR_SHOW_DESCRIPTION = "lockscreen_calendar_show_description"; + + /** + * Which calendars to look for events + * @hide + */ + public static final String LOCKSCREEN_CALENDARS = "lockscreen_calendars"; + + /** + * How far in the future to look for events + * @hide + */ + public static final String LOCKSCREEN_CALENDAR_LOOKAHEAD = "lockscreen_calendar_lookahead"; + + /** + * Whether to find only events with reminders + * @hide + */ + public static final String LOCKSCREEN_CALENDAR_REMINDERS_ONLY = "lockscreen_calendar_reminders_only"; + + /** + * Show the pending notification counts as overlays on the status bar + * @hide + */ + public static final String STATUS_BAR_NOTIF_COUNT = "status_bar_notif_count"; + + /** * Settings to backup. This is here so that it's in the same place as the settings * keys and easy to update. * @@ -2315,10 +2976,13 @@ public final class Settings { AUTO_TIME_ZONE, // moved to global TIME_12_24, DATE_FORMAT, + ACCELEROMETER_ROTATION, + USER_ROTATION, DTMF_TONE_WHEN_DIALING, DTMF_TONE_TYPE_WHEN_DIALING, HEARING_AID, TTY_MODE, + NOISE_SUPPRESSION, SOUND_EFFECTS_ENABLED, HAPTIC_FEEDBACK_ENABLED, POWER_SOUNDS_ENABLED, // moved to global @@ -2326,10 +2990,18 @@ public final class Settings { LOCKSCREEN_SOUNDS_ENABLED, SHOW_WEB_SUGGESTIONS, NOTIFICATION_LIGHT_PULSE, + NOTIFICATION_LIGHT_PULSE_DEFAULT_COLOR, + NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_ON, + NOTIFICATION_LIGHT_PULSE_DEFAULT_LED_OFF, SIP_CALL_OPTIONS, SIP_RECEIVE_CALLS, POINTER_SPEED, - VIBRATE_WHEN_RINGING + QUIET_HOURS_ENABLED, + QUIET_HOURS_START, + QUIET_HOURS_END, + QUIET_HOURS_MUTE, + QUIET_HOURS_STILL, + QUIET_HOURS_DIM, }; // Settings moved to Settings.Secure @@ -3082,6 +3754,12 @@ public final class Settings { public static final String ADB_ENABLED = Global.ADB_ENABLED; /** + * The TCP/IP port to run ADB on, or -1 for USB + * @hide + */ + public static final String ADB_PORT = "adb_port"; + + /** * The hostname for this device * @hide */ @@ -3261,6 +3939,13 @@ public final class Settings { "lock_screen_owner_info_enabled"; /** + * Whether the unsecure widget screen will be shown before a secure + * lock screen + * @hide + */ + public static final String LOCK_BEFORE_UNLOCK = + "lock_before_unlock"; + /** * The Logging ID (a unique 64-bit value) as a hex string. * Used as a pseudonymous identifier for logging. * @deprecated This identifier is poorly initialized and has @@ -3679,6 +4364,12 @@ public final class Settings { Global.WIFI_MOBILE_DATA_TRANSITION_WAKELOCK_TIMEOUT_MS; /** + * Whether the Wimax should be on. Only the WiMAX service should touch this. + * @hide + */ + public static final String WIMAX_ON = "wimax_on"; + + /** * Whether background data usage is allowed. * * @deprecated As of {@link VERSION_CODES#ICE_CREAM_SANDWICH}, @@ -4292,6 +4983,13 @@ public final class Settings { public static final String POWER_SOUNDS_ENABLED = "power_sounds_enabled"; /** + * Whether to allow killing of the foreground app by long-pressing the Back button + * @hide + */ + public static final String KILL_APP_LONGPRESS_BACK = "kill_app_longpress_back"; + + + /** * Whether we keep the device on while the device is plugged in. * Supported values are: * <ul> diff --git a/core/java/android/view/VolumePanel.java b/core/java/android/view/VolumePanel.java index d7c7f46..2497e95 100644 --- a/core/java/android/view/VolumePanel.java +++ b/core/java/android/view/VolumePanel.java @@ -35,7 +35,10 @@ import android.media.ToneGenerator; import android.net.Uri; import android.os.Handler; import android.os.Message; +import android.os.RemoteException; import android.os.Vibrator; +import android.provider.Settings; +import android.provider.Settings.System; import android.util.Log; import android.view.WindowManager.LayoutParams; import android.widget.ImageView; @@ -99,12 +102,16 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private static final int STREAM_MASTER = -100; // Pseudo stream type for remote volume is defined in AudioService.STREAM_REMOTE_MUSIC + public static final String ACTION_VOLUME_OVERLAY_CHANGED + = "android.intent.action.VOLUME_OVERLAY_CHANGED"; + protected Context mContext; private AudioManager mAudioManager; protected AudioService mAudioService; private boolean mRingIsSilent; private boolean mShowCombinedVolumes; private boolean mVoiceCapable; + private int mCurrentOverlayStyle = -1; // True if we want to play tones on the system stream when the master stream is specified. private final boolean mPlayMasterStreamTones; @@ -326,12 +333,26 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie mPlayMasterStreamTones = masterVolumeOnly && masterVolumeKeySounds; + // get the users preference + int choosenStyle = Settings.System.getInt(context.getContentResolver(),Settings.System.MODE_VOLUME_OVERLAY, -1); + // by default -1 is expected - deal with choosing the right default + if (choosenStyle == -1) { + if (mVoiceCapable) { + choosenStyle = Settings.System.VOLUME_OVERLAY_SINGLE; + } else { + choosenStyle = Settings.System.VOLUME_OVERLAY_EXPANDABLE; + } + } + changeOverlayStyle(choosenStyle); + mMoreButton.setOnClickListener(this); + listenToRingerMode(); } private void listenToRingerMode() { final IntentFilter filter = new IntentFilter(); filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); + filter.addAction(ACTION_VOLUME_OVERLAY_CHANGED); mContext.registerReceiver(new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { @@ -340,18 +361,45 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie if (AudioManager.RINGER_MODE_CHANGED_ACTION.equals(action)) { removeMessages(MSG_RINGER_MODE_CHANGED); sendMessage(obtainMessage(MSG_RINGER_MODE_CHANGED)); + } else if (ACTION_VOLUME_OVERLAY_CHANGED.equals(action)) { + int state = (Integer) intent.getExtra("state"); + changeOverlayStyle(state); } } }, filter); } - private boolean isMuted(int streamType) { - if (streamType == STREAM_MASTER) { - return mAudioManager.isMasterMute(); - } else if (streamType == AudioService.STREAM_REMOTE_MUSIC) { - return (mAudioService.getRemoteStreamVolume() <= 0); - } else { - return mAudioManager.isStreamMute(streamType); + private void changeOverlayStyle(int newStyle) { + Log.i("VolumePanel", "changeOverlayStyle : " + newStyle); + // Don't change to the same style + if (newStyle == mCurrentOverlayStyle) return; + switch (newStyle) { + case Settings.System.VOLUME_OVERLAY_SINGLE : + mMoreButton.setVisibility(View.GONE); + mDivider.setVisibility(View.GONE); + mShowCombinedVolumes = false; + mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_SINGLE; + break; + case Settings.System.VOLUME_OVERLAY_EXPANDABLE : + mMoreButton.setVisibility(View.VISIBLE); + mDivider.setVisibility(View.VISIBLE); + mShowCombinedVolumes = true; + mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_EXPANDABLE; + break; + case Settings.System.VOLUME_OVERLAY_EXPANDED : + mMoreButton.setVisibility(View.GONE); + mDivider.setVisibility(View.GONE); + mShowCombinedVolumes = true; + if (mCurrentOverlayStyle == Settings.System.VOLUME_OVERLAY_NONE) { + addOtherVolumes(); + expand(); + } + mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_EXPANDED; + break; + case Settings.System.VOLUME_OVERLAY_NONE : + mShowCombinedVolumes = false; + mCurrentOverlayStyle = Settings.System.VOLUME_OVERLAY_NONE; + break; } } @@ -385,6 +433,10 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie } } + private boolean isMuted(int streamType) { + return mAudioManager.isStreamMute(streamType); + } + private void createSliders() { LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); @@ -406,6 +458,7 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie sc.iconRes = streamRes.iconRes; sc.iconMuteRes = streamRes.iconMuteRes; sc.icon.setImageResource(sc.iconRes); + sc.icon.setOnClickListener(this); sc.seekbarView = (SeekBar) sc.group.findViewById(R.id.seekbar); int plusOne = (streamType == AudioSystem.STREAM_BLUETOOTH_SCO || streamType == AudioSystem.STREAM_VOICE_CALL) ? 1 : 0; @@ -442,6 +495,10 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie if (!STREAMS[i].show || streamType == mActiveStreamType) { continue; } + // Skip ring volume for non-phone devices + if (!mVoiceCapable && streamType == AudioManager.STREAM_RING) { + continue; + } StreamControl sc = mStreamControls.get(streamType); mSliderGroup.addView(sc.group); updateSlider(sc); @@ -475,10 +532,22 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie private void expand() { final int count = mSliderGroup.getChildCount(); for (int i = 0; i < count; i++) { - mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE); + if (mSliderGroup.getChildAt(i).getVisibility() != View.VISIBLE) { + mSliderGroup.getChildAt(i).setVisibility(View.VISIBLE); + } + } + mMoreButton.setVisibility(View.GONE); + mDivider.setVisibility(View.GONE); + } + + private void hideSlider(int mActiveStreamType) { + final int count = mSliderGroup.getChildCount(); + for (int i = 0; i < count; i++) { + StreamControl sc = (StreamControl) mSliderGroup.getChildAt(i).getTag(); + if (mActiveStreamType == sc.streamType) { + mSliderGroup.getChildAt(i).setVisibility(View.GONE); + } } - mMoreButton.setVisibility(View.INVISIBLE); - mDivider.setVisibility(View.INVISIBLE); } private void collapse() { @@ -578,8 +647,12 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie if ((flags & AudioManager.FLAG_SHOW_UI) != 0) { synchronized (this) { - if (mActiveStreamType != streamType) { - reorderSliders(streamType); + if (mActiveStreamType == -1 || streamType != mActiveStreamType) { + if (streamType != mActiveStreamType && + mCurrentOverlayStyle == Settings.System.VOLUME_OVERLAY_EXPANDABLE) { + hideSlider(mActiveStreamType); + } + reorderSliders(streamType); } onShowVolumeChanged(streamType, flags); } @@ -709,17 +782,32 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie } else { sc.seekbarView.setEnabled(true); } + // If adjusting Ring volume and preference is to link it to Notification + if (streamType == mAudioManager.STREAM_RING && + System.getInt(mContext.getContentResolver(),System.VOLUME_LINK_NOTIFICATION, 1) == 1) { + StreamControl notifySc = mStreamControls.get(mAudioManager.STREAM_NOTIFICATION); + if (index > notifySc.seekbarView.getMax()) { + notifySc.seekbarView.setProgress(notifySc.seekbarView.getMax()); + } else { + notifySc.seekbarView.setProgress(index); + } + } } - if (!mDialog.isShowing()) { + // Only Show if style needs it + if (!mDialog.isShowing() && mCurrentOverlayStyle != Settings.System.VOLUME_OVERLAY_NONE) { int stream = (streamType == AudioService.STREAM_REMOTE_MUSIC) ? -1 : streamType; // when the stream is for remote playback, use -1 to reset the stream type evaluation mAudioManager.forceVolumeControlStream(stream); mDialog.setContentView(mView); // Showing dialog - use collapsed state - if (mShowCombinedVolumes) { + if (mShowCombinedVolumes && mCurrentOverlayStyle != Settings.System.VOLUME_OVERLAY_EXPANDED) { collapse(); } + // If just changed the style and we need to expand + if (mCurrentOverlayStyle == Settings.System.VOLUME_OVERLAY_EXPANDED) { + expand(); + } mDialog.show(); } @@ -995,13 +1083,34 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie sendMessage(obtainMessage(MSG_TIMEOUT)); } - public void onProgressChanged(SeekBar seekBar, int progress, - boolean fromUser) { + public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { final Object tag = seekBar.getTag(); if (fromUser && tag instanceof StreamControl) { StreamControl sc = (StreamControl) tag; if (getStreamVolume(sc.streamType) != progress) { setStreamVolume(sc.streamType, progress, 0); + // if audio is linked then adjust other one if change made by user + if (fromUser && System.getInt(mContext.getContentResolver(),System.VOLUME_LINK_NOTIFICATION, 1) == 1) { + if (sc.streamType == AudioManager.STREAM_RING) { + StreamControl notifySc = mStreamControls.get(AudioManager.STREAM_NOTIFICATION); + if (notifySc != null) { + if (progress > notifySc.seekbarView.getMax()) { + notifySc.seekbarView.setProgress(notifySc.seekbarView.getMax()); + } else { + notifySc.seekbarView.setProgress(progress); + } + } + } else if (sc.streamType == AudioManager.STREAM_NOTIFICATION) { + StreamControl phoneSc = mStreamControls.get(AudioManager.STREAM_RING); + if (phoneSc != null) { + if (progress > phoneSc.seekbarView.getMax()) { + phoneSc.seekbarView.setProgress(phoneSc.seekbarView.getMax()); + } else { + phoneSc.seekbarView.setProgress(progress); + } + } + } + } } } resetTimeout(); @@ -1027,6 +1136,12 @@ public class VolumePanel extends Handler implements OnSeekBarChangeListener, Vie public void onClick(View v) { if (v == mMoreButton) { expand(); + } else if (v instanceof ImageView) { + Intent volumeSettings = new Intent(android.provider.Settings.ACTION_SOUND_SETTINGS); + volumeSettings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED); + forceTimeout(); + mContext.startActivity(volumeSettings); + return; } resetTimeout(); } diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java index 26739b3..fd5449c 100644 --- a/core/java/android/view/WindowManagerPolicy.java +++ b/core/java/android/view/WindowManagerPolicy.java @@ -399,6 +399,7 @@ public interface WindowManagerPolicy { public void shutdown(boolean confirm); public void rebootSafeMode(boolean confirm); + public void reboot(); } /** |