CMSDK: Introduce Profiles API from frameworks.
Refactor to create a system service in secondary CM framework. Change-Id: Ic69da01d941bbd09271c260429d744f8e79ab7b9
This commit is contained in:
parent
4e081aef67
commit
4334b3d969
@ -0,0 +1,616 @@
|
||||
/*
|
||||
* Copyright (c) 2011-2014 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 org.cyanogenmod.platform.internal;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import org.xmlpull.v1.XmlPullParserFactory;
|
||||
|
||||
import android.app.ActivityManagerNative;
|
||||
import android.app.NotificationGroup;
|
||||
import android.app.backup.BackupManager;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.os.Environment;
|
||||
import android.os.UserHandle;
|
||||
import android.os.IBinder;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
import android.os.ParcelUuid;
|
||||
|
||||
import com.android.server.SystemService;
|
||||
|
||||
import cyanogenmod.app.CMContextConstants;
|
||||
import cyanogenmod.app.Profile;
|
||||
import cyanogenmod.app.ProfileGroup;
|
||||
import cyanogenmod.app.ProfileManager;
|
||||
import cyanogenmod.app.IProfileManager;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.io.IOException;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
/** {@hide} */
|
||||
public class ProfileManagerService extends SystemService {
|
||||
|
||||
private static final String TAG = "CMProfileService";
|
||||
// Enable the below for detailed logging of this class
|
||||
private static final boolean LOCAL_LOGV = false;
|
||||
|
||||
public static final String PERMISSION_CHANGE_SETTINGS = "android.permission.WRITE_SETTINGS";
|
||||
|
||||
/* package */ static final File PROFILE_FILE =
|
||||
new File(Environment.getSystemSecureDirectory(), "profiles.xml");
|
||||
|
||||
private Map<UUID, Profile> mProfiles;
|
||||
|
||||
// Match UUIDs and names, used for reverse compatibility
|
||||
private Map<String, UUID> mProfileNames;
|
||||
|
||||
private Map<UUID, NotificationGroup> mGroups;
|
||||
|
||||
private Profile mActiveProfile;
|
||||
|
||||
// Well-known UUID of the wildcard group
|
||||
private static final UUID mWildcardUUID =
|
||||
UUID.fromString("a126d48a-aaef-47c4-baed-7f0e44aeffe5");
|
||||
private NotificationGroup mWildcardGroup;
|
||||
|
||||
private Context mContext;
|
||||
private boolean mDirty;
|
||||
private BackupManager mBackupManager;
|
||||
|
||||
private BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
if (action.equals(Intent.ACTION_LOCALE_CHANGED)) {
|
||||
persistIfDirty();
|
||||
initialize();
|
||||
} else if (action.equals(Intent.ACTION_SHUTDOWN)) {
|
||||
persistIfDirty();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public ProfileManagerService(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
publishBinderService(CMContextConstants.CM_PROFILE_SERVICE, mService);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStart() {
|
||||
mBackupManager = new BackupManager(mContext);
|
||||
|
||||
mWildcardGroup = new NotificationGroup(
|
||||
mContext.getString(com.android.internal.R.string.wildcardProfile),
|
||||
com.android.internal.R.string.wildcardProfile,
|
||||
mWildcardUUID);
|
||||
|
||||
initialize();
|
||||
|
||||
IntentFilter filter = new IntentFilter();
|
||||
filter.addAction(Intent.ACTION_LOCALE_CHANGED);
|
||||
filter.addAction(Intent.ACTION_SHUTDOWN);
|
||||
mContext.registerReceiver(mIntentReceiver, filter);
|
||||
}
|
||||
|
||||
private void initialize() {
|
||||
initialize(false);
|
||||
}
|
||||
|
||||
private void initialize(boolean skipFile) {
|
||||
mProfiles = new HashMap<UUID, Profile>();
|
||||
mProfileNames = new HashMap<String, UUID>();
|
||||
mGroups = new HashMap<UUID, NotificationGroup>();
|
||||
mDirty = false;
|
||||
|
||||
boolean init = skipFile;
|
||||
|
||||
if (!skipFile) {
|
||||
try {
|
||||
loadFromFile();
|
||||
} catch (XmlPullParserException e) {
|
||||
init = true;
|
||||
} catch (IOException e) {
|
||||
init = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (init) {
|
||||
try {
|
||||
initialiseStructure();
|
||||
} catch (Throwable ex) {
|
||||
Log.e(TAG, "Error loading xml from resource: ", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private final IBinder mService = new IProfileManager.Stub() {
|
||||
|
||||
@Override
|
||||
public void resetAll() {
|
||||
enforceChangePermissions();
|
||||
initialize(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean setActiveProfileByName(String profileName) {
|
||||
if (!mProfileNames.containsKey(profileName)) {
|
||||
// Since profileName could not be casted into a UUID, we can call it a string.
|
||||
Log.w(TAG, "Unable to find profile to set active, based on string: " + profileName);
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LOCAL_LOGV) {
|
||||
Log.v(TAG, "setActiveProfile(String) found profile name in mProfileNames.");
|
||||
}
|
||||
/*
|
||||
* We need to clear the caller's identity in order to
|
||||
* - allow the profile switch to execute actions
|
||||
* not included in the caller's permissions
|
||||
* - broadcast INTENT_ACTION_PROFILE_SELECTED
|
||||
*/
|
||||
long token = clearCallingIdentity();
|
||||
setActiveProfileInternal(mProfiles.get(mProfileNames.get(profileName)), true);
|
||||
restoreCallingIdentity(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean setActiveProfile(ParcelUuid profileParcelUuid) {
|
||||
/*
|
||||
* We need to clear the caller's identity in order to
|
||||
* - allow the profile switch to execute actions
|
||||
* not included in the caller's permissions
|
||||
* - broadcast INTENT_ACTION_PROFILE_SELECTED
|
||||
*/
|
||||
long token = clearCallingIdentity();
|
||||
boolean ret = setActiveProfileInternal(profileParcelUuid.getUuid(), true);
|
||||
restoreCallingIdentity(token);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean addProfile(Profile profile) {
|
||||
enforceChangePermissions();
|
||||
addProfileInternal(profile);
|
||||
long token = clearCallingIdentity();
|
||||
persistIfDirty();
|
||||
restoreCallingIdentity(token);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public Profile getProfileByName(String profileName) {
|
||||
if (mProfileNames.containsKey(profileName)) {
|
||||
return mProfiles.get(mProfileNames.get(profileName));
|
||||
} else if (mProfiles.containsKey(UUID.fromString((profileName)))) {
|
||||
return mProfiles.get(UUID.fromString(profileName));
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Profile getProfile(ParcelUuid profileParcelUuid) {
|
||||
UUID profileUuid = profileParcelUuid.getUuid();
|
||||
return internalGetProfile(profileUuid);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Profile[] getProfiles() {
|
||||
Profile[] profiles = getProfileList().toArray(new Profile[mProfiles.size()]);
|
||||
Arrays.sort(profiles);
|
||||
return profiles;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Profile getActiveProfile() {
|
||||
return mActiveProfile;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean removeProfile(Profile profile) {
|
||||
enforceChangePermissions();
|
||||
if (mProfileNames.remove(profile.getName()) != null
|
||||
&& mProfiles.remove(profile.getUuid()) != null) {
|
||||
mDirty = true;
|
||||
long token = clearCallingIdentity();
|
||||
persistIfDirty();
|
||||
restoreCallingIdentity(token);
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateProfile(Profile profile) {
|
||||
enforceChangePermissions();
|
||||
Profile old = mProfiles.get(profile.getUuid());
|
||||
|
||||
if (old == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mProfileNames.remove(old.getName());
|
||||
mProfileNames.put(profile.getName(), profile.getUuid());
|
||||
mProfiles.put(profile.getUuid(), profile);
|
||||
/* no need to set mDirty, if the profile was actually changed,
|
||||
* it's marked as dirty by itself */
|
||||
long token = clearCallingIdentity();
|
||||
persistIfDirty();
|
||||
|
||||
// Also update if we changed the active profile
|
||||
if (mActiveProfile != null && mActiveProfile.getUuid().equals(profile.getUuid())) {
|
||||
setActiveProfileInternal(profile, true);
|
||||
}
|
||||
restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean profileExists(ParcelUuid profileUuid) {
|
||||
return mProfiles.containsKey(profileUuid.getUuid());
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean profileExistsByName(String profileName) {
|
||||
for (Map.Entry<String, UUID> entry : mProfileNames.entrySet()) {
|
||||
if (entry.getKey().equalsIgnoreCase(profileName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Deprecated
|
||||
public boolean notificationGroupExistsByName(String notificationGroupName) {
|
||||
for (NotificationGroup group : mGroups.values()) {
|
||||
if (group.getName().equalsIgnoreCase(notificationGroupName)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationGroup[] getNotificationGroups() {
|
||||
return mGroups.values().toArray(new NotificationGroup[mGroups.size()]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addNotificationGroup(NotificationGroup group) {
|
||||
enforceChangePermissions();
|
||||
addNotificationGroupInternal(group);
|
||||
long token = clearCallingIdentity();
|
||||
persistIfDirty();
|
||||
restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeNotificationGroup(NotificationGroup group) {
|
||||
enforceChangePermissions();
|
||||
mDirty |= mGroups.remove(group.getUuid()) != null;
|
||||
// Remove the corresponding ProfileGroup from all the profiles too if
|
||||
// they use it.
|
||||
for (Profile profile : mProfiles.values()) {
|
||||
profile.removeProfileGroup(group.getUuid());
|
||||
}
|
||||
long token = clearCallingIdentity();
|
||||
persistIfDirty();
|
||||
restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateNotificationGroup(NotificationGroup group) {
|
||||
enforceChangePermissions();
|
||||
NotificationGroup old = mGroups.get(group.getUuid());
|
||||
if (old == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mGroups.put(group.getUuid(), group);
|
||||
/* no need to set mDirty, if the group was actually changed,
|
||||
* it's marked as dirty by itself */
|
||||
long token = clearCallingIdentity();
|
||||
persistIfDirty();
|
||||
restoreCallingIdentity(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationGroup getNotificationGroupForPackage(String pkg) {
|
||||
for (NotificationGroup group : mGroups.values()) {
|
||||
if (group.hasPackage(pkg)) {
|
||||
return group;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NotificationGroup getNotificationGroup(ParcelUuid uuid) {
|
||||
if (uuid.getUuid().equals(mWildcardGroup.getUuid())) {
|
||||
return mWildcardGroup;
|
||||
}
|
||||
return mGroups.get(uuid.getUuid());
|
||||
}
|
||||
};
|
||||
|
||||
private void addProfileInternal(Profile profile) {
|
||||
// Make sure this profile has all of the correct groups.
|
||||
for (NotificationGroup group : mGroups.values()) {
|
||||
ensureGroupInProfile(profile, group, false);
|
||||
}
|
||||
ensureGroupInProfile(profile, mWildcardGroup, true);
|
||||
mProfiles.put(profile.getUuid(), profile);
|
||||
mProfileNames.put(profile.getName(), profile.getUuid());
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
private void ensureGroupInProfile(Profile profile,
|
||||
NotificationGroup group, boolean defaultGroup) {
|
||||
if (profile.getProfileGroup(group.getUuid()) != null) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* enforce a matchup between profile and notification group, which not only
|
||||
* works by UUID, but also by name for backwards compatibility */
|
||||
for (ProfileGroup pg : profile.getProfileGroups()) {
|
||||
if (pg.matches(group, defaultGroup)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/* didn't find any, create new group */
|
||||
profile.addProfileGroup(new ProfileGroup(group.getUuid(), defaultGroup));
|
||||
}
|
||||
|
||||
private Profile internalGetProfile(UUID profileUuid) {
|
||||
// use primary UUID first
|
||||
if (mProfiles.containsKey(profileUuid)) {
|
||||
return mProfiles.get(profileUuid);
|
||||
}
|
||||
// if no match was found: try secondary UUID
|
||||
for (Profile p : mProfiles.values()) {
|
||||
for (UUID uuid : p.getSecondaryUuids()) {
|
||||
if (profileUuid.equals(uuid)) {
|
||||
return p;
|
||||
}
|
||||
}
|
||||
}
|
||||
// nothing found
|
||||
return null;
|
||||
}
|
||||
|
||||
/* package */ Collection<Profile> getProfileList() {
|
||||
return mProfiles.values();
|
||||
}
|
||||
|
||||
private String getXmlString() {
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("<profiles>\n<active>");
|
||||
builder.append(TextUtils.htmlEncode(mActiveProfile.getUuid().toString()));
|
||||
builder.append("</active>\n");
|
||||
|
||||
for (Profile p : mProfiles.values()) {
|
||||
p.getXmlString(builder, mContext);
|
||||
}
|
||||
for (NotificationGroup g : mGroups.values()) {
|
||||
g.getXmlString(builder, mContext);
|
||||
}
|
||||
builder.append("</profiles>\n");
|
||||
return builder.toString();
|
||||
}
|
||||
|
||||
private synchronized void persistIfDirty() {
|
||||
boolean dirty = mDirty;
|
||||
if (!dirty) {
|
||||
for (Profile profile : mProfiles.values()) {
|
||||
if (profile.isDirty()) {
|
||||
dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!dirty) {
|
||||
for (NotificationGroup group : mGroups.values()) {
|
||||
if (group.isDirty()) {
|
||||
dirty = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (dirty) {
|
||||
try {
|
||||
Log.d(TAG, "Saving profile data...");
|
||||
FileWriter fw = new FileWriter(PROFILE_FILE);
|
||||
fw.write(getXmlString());
|
||||
fw.close();
|
||||
Log.d(TAG, "Save completed.");
|
||||
mDirty = false;
|
||||
mBackupManager.dataChanged();
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void enforceChangePermissions() {
|
||||
mContext.enforceCallingOrSelfPermission(PERMISSION_CHANGE_SETTINGS,
|
||||
"You do not have permissions to change the Profile Manager.");
|
||||
}
|
||||
|
||||
// Called by SystemBackupAgent after files are restored to disk.
|
||||
void settingsRestored() {
|
||||
initialize();
|
||||
for (Profile p : mProfiles.values()) {
|
||||
p.validateRingtones(mContext);
|
||||
}
|
||||
persistIfDirty();
|
||||
}
|
||||
|
||||
private void loadFromFile() throws XmlPullParserException, IOException {
|
||||
XmlPullParserFactory xppf = XmlPullParserFactory.newInstance();
|
||||
XmlPullParser xpp = xppf.newPullParser();
|
||||
FileReader fr = new FileReader(PROFILE_FILE);
|
||||
xpp.setInput(fr);
|
||||
loadXml(xpp, mContext);
|
||||
fr.close();
|
||||
persistIfDirty();
|
||||
}
|
||||
|
||||
private void loadXml(XmlPullParser xpp, Context context) throws
|
||||
XmlPullParserException, IOException {
|
||||
int event = xpp.next();
|
||||
String active = null;
|
||||
while (event != XmlPullParser.END_TAG || !"profiles".equals(xpp.getName())) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
String name = xpp.getName();
|
||||
if (name.equals("active")) {
|
||||
active = xpp.nextText();
|
||||
Log.d(TAG, "Found active: " + active);
|
||||
} else if (name.equals("profile")) {
|
||||
Profile prof = Profile.fromXml(xpp, context);
|
||||
addProfileInternal(prof);
|
||||
// Failsafe if no active found
|
||||
if (active == null) {
|
||||
active = prof.getUuid().toString();
|
||||
}
|
||||
} else if (name.equals("notificationGroup")) {
|
||||
NotificationGroup ng = NotificationGroup.fromXml(xpp, context);
|
||||
addNotificationGroupInternal(ng);
|
||||
}
|
||||
} else if (event == XmlPullParser.END_DOCUMENT) {
|
||||
throw new IOException("Premature end of file while reading " + PROFILE_FILE);
|
||||
}
|
||||
event = xpp.next();
|
||||
}
|
||||
// Don't do initialisation on startup. The AudioManager doesn't exist yet
|
||||
// and besides, the volume settings will have survived the reboot.
|
||||
try {
|
||||
// Try / catch block to detect if XML file needs to be upgraded.
|
||||
setActiveProfileInternal(UUID.fromString(active), false);
|
||||
} catch (IllegalArgumentException e) {
|
||||
if (mProfileNames.containsKey(active)) {
|
||||
setActiveProfileInternal(mProfileNames.get(active), false);
|
||||
} else {
|
||||
// Final fail-safe: We must have SOME profile active.
|
||||
// If we couldn't select one by now, we'll pick the first in the set.
|
||||
setActiveProfileInternal(mProfiles.values().iterator().next(), false);
|
||||
}
|
||||
// This is a hint that we probably just upgraded the XML file. Save changes.
|
||||
mDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void initialiseStructure() throws XmlPullParserException, IOException {
|
||||
XmlResourceParser xml = mContext.getResources().getXml(
|
||||
com.android.internal.R.xml.profile_default);
|
||||
try {
|
||||
loadXml(xml, mContext);
|
||||
mDirty = true;
|
||||
persistIfDirty();
|
||||
} finally {
|
||||
xml.close();
|
||||
}
|
||||
}
|
||||
|
||||
private boolean setActiveProfileInternal(UUID profileUuid, boolean doInit) {
|
||||
if (!mProfiles.containsKey(profileUuid)) {
|
||||
Log.e(TAG, "Cannot set active profile to: "
|
||||
+ profileUuid.toString() + " - does not exist.");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (LOCAL_LOGV) Log.v(TAG, "setActiveProfile(UUID, boolean) found UUID in mProfiles.");
|
||||
setActiveProfileInternal(mProfiles.get(profileUuid), doInit);
|
||||
return true;
|
||||
}
|
||||
|
||||
/* package */ void setActiveProfileInternal(Profile newActiveProfile, boolean doInit) {
|
||||
/*
|
||||
* NOTE: Since this is not a public function, and all public functions
|
||||
* take either a string or a UUID, the active profile should always be
|
||||
* in the collection. If writing another setActiveProfile which receives
|
||||
* a Profile object, run enforceChangePermissions, add the profile to the
|
||||
* list, and THEN add it.
|
||||
*/
|
||||
|
||||
enforceChangePermissions();
|
||||
|
||||
Log.d(TAG, "Set active profile to: " + newActiveProfile.getUuid().toString()
|
||||
+ " - " + newActiveProfile.getName());
|
||||
|
||||
Profile lastProfile = mActiveProfile;
|
||||
mActiveProfile = newActiveProfile;
|
||||
mDirty = true;
|
||||
|
||||
if (doInit) {
|
||||
if (LOCAL_LOGV) Log.v(TAG, "setActiveProfile(Profile, boolean) - Running init");
|
||||
// Call profile's "doSelect"
|
||||
mActiveProfile.doSelect(mContext);
|
||||
|
||||
// Notify other applications of newly selected profile.
|
||||
Intent broadcast = new Intent(ProfileManager.INTENT_ACTION_PROFILE_SELECTED);
|
||||
broadcast.putExtra(ProfileManager.EXTRA_PROFILE_NAME,
|
||||
mActiveProfile.getName());
|
||||
broadcast.putExtra(ProfileManager.EXTRA_PROFILE_UUID,
|
||||
mActiveProfile.getUuid().toString());
|
||||
broadcast.putExtra(ProfileManager.EXTRA_LAST_PROFILE_NAME,
|
||||
lastProfile.getName());
|
||||
broadcast.putExtra(ProfileManager.EXTRA_LAST_PROFILE_UUID,
|
||||
lastProfile.getUuid().toString());
|
||||
|
||||
mContext.sendBroadcastAsUser(broadcast, UserHandle.ALL);
|
||||
persistIfDirty();
|
||||
} else if (lastProfile != mActiveProfile && ActivityManagerNative.isSystemReady()) {
|
||||
// Something definitely changed: notify.
|
||||
Intent broadcast = new Intent(ProfileManager.INTENT_ACTION_PROFILE_UPDATED);
|
||||
broadcast.putExtra(ProfileManager.EXTRA_PROFILE_NAME,
|
||||
mActiveProfile.getName());
|
||||
broadcast.putExtra(ProfileManager.EXTRA_PROFILE_UUID,
|
||||
mActiveProfile.getUuid().toString());
|
||||
mContext.sendBroadcastAsUser(broadcast, UserHandle.ALL);
|
||||
}
|
||||
}
|
||||
|
||||
private void addNotificationGroupInternal(NotificationGroup group) {
|
||||
if (mGroups.put(group.getUuid(), group) == null) {
|
||||
// If the above is true, then the ProfileGroup shouldn't exist in
|
||||
// the profile. Ensure it is added.
|
||||
for (Profile profile : mProfiles.values()) {
|
||||
ensureGroupInProfile(profile, group, false);
|
||||
}
|
||||
}
|
||||
mDirty = true;
|
||||
}
|
||||
}
|
@ -39,4 +39,15 @@ public final class CMContextConstants {
|
||||
*/
|
||||
public static final String CM_STATUS_BAR_SERVICE = "cmstatusbar";
|
||||
|
||||
/**
|
||||
* Use with {@link android.content.Context#getSystemService} to retrieve a
|
||||
* {@link cyanogenmod.app.ProfileManager} for informing the user of
|
||||
* background events.
|
||||
*
|
||||
* @see android.content.Context#getSystemService
|
||||
* @see cyanogenmod.app.ProfileManager
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public static final String CM_PROFILE_SERVICE = "profile";
|
||||
}
|
||||
|
50
src/java/cyanogenmod/app/IProfileManager.aidl
Normal file
50
src/java/cyanogenmod/app/IProfileManager.aidl
Normal file
@ -0,0 +1,50 @@
|
||||
/* //device/java/android/android/app/IProfileManager.aidl
|
||||
**
|
||||
** Copyright (C) 2015 The CyanogenMod Project
|
||||
**
|
||||
** Licensed under the Apache License, Version 2.0 (the "License");
|
||||
** you may not use this file except in compliance with the License.
|
||||
** You may obtain a copy of the License at
|
||||
**
|
||||
** http://www.apache.org/licenses/LICENSE-2.0
|
||||
**
|
||||
** Unless required by applicable law or agreed to in writing, software
|
||||
** distributed under the License is distributed on an "AS IS" BASIS,
|
||||
** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
** See the License for the specific language governing permissions and
|
||||
** limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import cyanogenmod.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();
|
||||
}
|
19
src/java/cyanogenmod/app/Profile.aidl
Normal file
19
src/java/cyanogenmod/app/Profile.aidl
Normal file
@ -0,0 +1,19 @@
|
||||
/**
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
parcelable Profile;
|
869
src/java/cyanogenmod/app/Profile.java
Executable file
869
src/java/cyanogenmod/app/Profile.java
Executable file
@ -0,0 +1,869 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import android.app.AirplaneModeSettings;
|
||||
import android.app.BrightnessSettings;
|
||||
import android.app.ConnectionSettings;
|
||||
import android.app.RingModeSettings;
|
||||
import android.app.StreamSettings;
|
||||
import android.content.Context;
|
||||
import android.media.AudioManager;
|
||||
import android.os.Parcel;
|
||||
import android.os.ParcelUuid;
|
||||
import android.os.Parcelable;
|
||||
import android.os.UserHandle;
|
||||
import android.provider.Settings;
|
||||
import android.text.TextUtils;
|
||||
import android.util.Log;
|
||||
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* @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<String, ProfileTrigger> mTriggers = new HashMap<String, ProfileTrigger>();
|
||||
|
||||
private Map<Integer, ConnectionSettings> connections = new HashMap<Integer, ConnectionSettings>();
|
||||
|
||||
private RingModeSettings mRingMode = new RingModeSettings();
|
||||
|
||||
private AirplaneModeSettings mAirplaneMode = new AirplaneModeSettings();
|
||||
|
||||
private BrightnessSettings mBrightness = new BrightnessSettings();
|
||||
|
||||
private int mScreenLockMode = LockMode.DEFAULT;
|
||||
|
||||
private int mExpandedDesktopMode = ExpandedDesktopMode.DEFAULT;
|
||||
|
||||
private int mDozeMode = DozeMode.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 ExpandedDesktopMode {
|
||||
public static final int DEFAULT = 0;
|
||||
public static final int ENABLE = 1;
|
||||
public static final int DISABLE = 2;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static class DozeMode {
|
||||
public static final int DEFAULT = 0;
|
||||
public static final int ENABLE = 1;
|
||||
public static final int DISABLE = 2;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static class TriggerType {
|
||||
public static final int WIFI = 0;
|
||||
public static final int BLUETOOTH = 1;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static class TriggerState {
|
||||
public static final int ON_CONNECT = 0;
|
||||
public static final int ON_DISCONNECT = 1;
|
||||
public static final int DISABLED = 2;
|
||||
public static final int ON_A2DP_CONNECT = 3;
|
||||
public static final int ON_A2DP_DISCONNECT = 4;
|
||||
}
|
||||
|
||||
public static class ProfileTrigger implements Parcelable {
|
||||
private int mType;
|
||||
private String mId;
|
||||
private String mName;
|
||||
private int mState;
|
||||
|
||||
public ProfileTrigger(int type, String id, int state, String name) {
|
||||
mType = type;
|
||||
mId = id;
|
||||
mState = state;
|
||||
mName = name;
|
||||
}
|
||||
|
||||
private ProfileTrigger(Parcel in) {
|
||||
mType = in.readInt();
|
||||
mId = in.readString();
|
||||
mState = in.readInt();
|
||||
mName = in.readString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(mType);
|
||||
dest.writeString(mId);
|
||||
dest.writeInt(mState);
|
||||
dest.writeString(mName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getType() {
|
||||
return mType;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return mName;
|
||||
}
|
||||
|
||||
public String getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public int getState() {
|
||||
return mState;
|
||||
}
|
||||
|
||||
public void getXmlString(StringBuilder builder, Context context) {
|
||||
final String itemType = mType == TriggerType.WIFI ? "wifiAP" : "btDevice";
|
||||
|
||||
builder.append("<");
|
||||
builder.append(itemType);
|
||||
builder.append(" ");
|
||||
builder.append(getIdType(mType));
|
||||
builder.append("=\"");
|
||||
builder.append(mId);
|
||||
builder.append("\" state=\"");
|
||||
builder.append(mState);
|
||||
builder.append("\" name=\"");
|
||||
builder.append(mName);
|
||||
builder.append("\"></");
|
||||
builder.append(itemType);
|
||||
builder.append(">\n");
|
||||
}
|
||||
|
||||
public static ProfileTrigger fromXml(XmlPullParser xpp, Context context) {
|
||||
final String name = xpp.getName();
|
||||
final int type;
|
||||
|
||||
if (name.equals("wifiAP")) {
|
||||
type = TriggerType.WIFI;
|
||||
} else if (name.equals("btDevice")) {
|
||||
type = TriggerType.BLUETOOTH;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
|
||||
String id = xpp.getAttributeValue(null, getIdType(type));
|
||||
int state = Integer.valueOf(xpp.getAttributeValue(null, "state"));
|
||||
String triggerName = xpp.getAttributeValue(null, "name");
|
||||
if (triggerName == null) {
|
||||
triggerName = id;
|
||||
}
|
||||
|
||||
return new ProfileTrigger(type, id, state, triggerName);
|
||||
}
|
||||
|
||||
private static String getIdType(int type) {
|
||||
return type == TriggerType.WIFI ? "ssid" : "address";
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<ProfileTrigger> CREATOR
|
||||
= new Parcelable.Creator<ProfileTrigger>() {
|
||||
public ProfileTrigger createFromParcel(Parcel in) {
|
||||
return new ProfileTrigger(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProfileTrigger[] newArray(int size) {
|
||||
return new ProfileTrigger[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static final Parcelable.Creator<Profile> CREATOR = new Parcelable.Creator<Profile>() {
|
||||
public Profile createFromParcel(Parcel in) {
|
||||
return new Profile(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Profile[] newArray(int size) {
|
||||
return new Profile[size];
|
||||
}
|
||||
};
|
||||
|
||||
/** @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 getTrigger(int type, String id) {
|
||||
ProfileTrigger trigger = id != null ? mTriggers.get(id) : null;
|
||||
if (trigger != null) {
|
||||
return trigger.mState;
|
||||
}
|
||||
return TriggerState.DISABLED;
|
||||
}
|
||||
|
||||
public ArrayList<ProfileTrigger> getTriggersFromType(int type) {
|
||||
ArrayList<ProfileTrigger> result = new ArrayList<ProfileTrigger>();
|
||||
for (Entry<String, ProfileTrigger> profileTrigger: mTriggers.entrySet()) {
|
||||
ProfileTrigger trigger = profileTrigger.getValue();
|
||||
if (trigger.getType() == type) {
|
||||
result.add(trigger);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void setTrigger(int type, String id, int state, String name) {
|
||||
if (id == null
|
||||
|| type < TriggerType.WIFI || type > TriggerType.BLUETOOTH
|
||||
|| state < TriggerState.ON_CONNECT || state > TriggerState.ON_A2DP_DISCONNECT) {
|
||||
return;
|
||||
}
|
||||
|
||||
ProfileTrigger trigger = mTriggers.get(id);
|
||||
|
||||
if (state == TriggerState.DISABLED) {
|
||||
if (trigger != null) {
|
||||
mTriggers.remove(id);
|
||||
}
|
||||
} else if (trigger != null) {
|
||||
trigger.mState = state;
|
||||
} else {
|
||||
mTriggers.put(id, new ProfileTrigger(type, id, state, name));
|
||||
}
|
||||
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
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.writeParcelable(mRingMode, flags);
|
||||
dest.writeParcelable(mAirplaneMode, flags);
|
||||
dest.writeParcelable(mBrightness, flags);
|
||||
dest.writeInt(mScreenLockMode);
|
||||
dest.writeMap(mTriggers);
|
||||
dest.writeInt(mExpandedDesktopMode);
|
||||
dest.writeInt(mDozeMode);
|
||||
}
|
||||
|
||||
/** @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);
|
||||
}
|
||||
mRingMode = (RingModeSettings) in.readParcelable(null);
|
||||
mAirplaneMode = (AirplaneModeSettings) in.readParcelable(null);
|
||||
mBrightness = (BrightnessSettings) in.readParcelable(null);
|
||||
mScreenLockMode = in.readInt();
|
||||
in.readMap(mTriggers, null);
|
||||
mExpandedDesktopMode = in.readInt();
|
||||
mDozeMode = 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 RingModeSettings getRingMode() {
|
||||
return mRingMode;
|
||||
}
|
||||
|
||||
public void setRingMode(RingModeSettings descriptor) {
|
||||
mRingMode = descriptor;
|
||||
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 getExpandedDesktopMode() {
|
||||
return mExpandedDesktopMode;
|
||||
}
|
||||
|
||||
public void setExpandedDesktopMode(int expandedDesktopMode) {
|
||||
if (expandedDesktopMode < ExpandedDesktopMode.DEFAULT
|
||||
|| expandedDesktopMode > ExpandedDesktopMode.DISABLE) {
|
||||
mExpandedDesktopMode = ExpandedDesktopMode.DEFAULT;
|
||||
} else {
|
||||
mExpandedDesktopMode = expandedDesktopMode;
|
||||
}
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
public int getDozeMode() {
|
||||
return mDozeMode;
|
||||
}
|
||||
|
||||
public void setDozeMode(int dozeMode) {
|
||||
if (dozeMode < DozeMode.DEFAULT
|
||||
|| dozeMode > DozeMode.DISABLE) {
|
||||
mDozeMode = DozeMode.DEFAULT;
|
||||
} else {
|
||||
mDozeMode = dozeMode;
|
||||
}
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
public AirplaneModeSettings getAirplaneMode() {
|
||||
return mAirplaneMode;
|
||||
}
|
||||
|
||||
public void setAirplaneMode(AirplaneModeSettings descriptor) {
|
||||
mAirplaneMode = descriptor;
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
public BrightnessSettings getBrightness() {
|
||||
return mBrightness;
|
||||
}
|
||||
|
||||
public void setBrightness(BrightnessSettings descriptor) {
|
||||
mBrightness = descriptor;
|
||||
mDirty = true;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public boolean isDirty() {
|
||||
if (mDirty) {
|
||||
return true;
|
||||
}
|
||||
for (ProfileGroup group : profileGroups.values()) {
|
||||
if (group.isDirty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (StreamSettings stream : streams.values()) {
|
||||
if (stream.isDirty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
for (ConnectionSettings conn : connections.values()) {
|
||||
if (conn.isDirty()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
if (mRingMode.isDirty()) {
|
||||
return true;
|
||||
}
|
||||
if (mAirplaneMode.isDirty()) {
|
||||
return true;
|
||||
}
|
||||
if (mBrightness.isDirty()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void getXmlString(StringBuilder builder, Context context) {
|
||||
builder.append("<profile ");
|
||||
if (mNameResId > 0) {
|
||||
builder.append("nameres=\"");
|
||||
builder.append(context.getResources().getResourceEntryName(mNameResId));
|
||||
} else {
|
||||
builder.append("name=\"");
|
||||
builder.append(TextUtils.htmlEncode(getName()));
|
||||
}
|
||||
builder.append("\" uuid=\"");
|
||||
builder.append(TextUtils.htmlEncode(getUuid().toString()));
|
||||
builder.append("\">\n");
|
||||
|
||||
builder.append("<uuids>");
|
||||
for (UUID u : mSecondaryUuids) {
|
||||
builder.append("<uuid>");
|
||||
builder.append(TextUtils.htmlEncode(u.toString()));
|
||||
builder.append("</uuid>");
|
||||
}
|
||||
builder.append("</uuids>\n");
|
||||
|
||||
builder.append("<profiletype>");
|
||||
builder.append(getProfileType() == 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("<expanded-desktop-mode>");
|
||||
builder.append(mExpandedDesktopMode);
|
||||
builder.append("</expanded-desktop-mode>\n");
|
||||
|
||||
builder.append("<doze-mode>");
|
||||
builder.append(mDozeMode);
|
||||
builder.append("</doze-mode>\n");
|
||||
|
||||
mAirplaneMode.getXmlString(builder, context);
|
||||
|
||||
mBrightness.getXmlString(builder, context);
|
||||
|
||||
mRingMode.getXmlString(builder, context);
|
||||
|
||||
for (ProfileGroup pGroup : profileGroups.values()) {
|
||||
pGroup.getXmlString(builder, context);
|
||||
}
|
||||
for (StreamSettings sd : streams.values()) {
|
||||
sd.getXmlString(builder, context);
|
||||
}
|
||||
for (ConnectionSettings cs : connections.values()) {
|
||||
cs.getXmlString(builder, context);
|
||||
}
|
||||
if (!mTriggers.isEmpty()) {
|
||||
builder.append("<triggers>\n");
|
||||
for (ProfileTrigger trigger : mTriggers.values()) {
|
||||
trigger.getXmlString(builder, context);
|
||||
}
|
||||
builder.append("</triggers>\n");
|
||||
}
|
||||
|
||||
builder.append("</profile>\n");
|
||||
mDirty = false;
|
||||
}
|
||||
|
||||
private static List<UUID> readSecondaryUuidsFromXml(XmlPullParser xpp, Context context)
|
||||
throws XmlPullParserException,
|
||||
IOException {
|
||||
ArrayList<UUID> uuids = new ArrayList<UUID>();
|
||||
int event = xpp.next();
|
||||
while (event != XmlPullParser.END_TAG || !xpp.getName().equals("uuids")) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
String name = xpp.getName();
|
||||
if (name.equals("uuid")) {
|
||||
try {
|
||||
uuids.add(UUID.fromString(xpp.nextText()));
|
||||
} catch (NullPointerException e) {
|
||||
Log.w(TAG, "Null Pointer - invalid UUID");
|
||||
} catch (IllegalArgumentException e) {
|
||||
Log.w(TAG, "UUID not recognized");
|
||||
}
|
||||
}
|
||||
}
|
||||
event = xpp.next();
|
||||
}
|
||||
return uuids;
|
||||
}
|
||||
|
||||
private static void readTriggersFromXml(XmlPullParser xpp, Context context, Profile profile)
|
||||
throws XmlPullParserException, IOException {
|
||||
int event = xpp.next();
|
||||
while (event != XmlPullParser.END_TAG || !xpp.getName().equals("triggers")) {
|
||||
if (event == XmlPullParser.START_TAG) {
|
||||
ProfileTrigger trigger = ProfileTrigger.fromXml(xpp, context);
|
||||
if (trigger != null) {
|
||||
profile.mTriggers.put(trigger.mId, trigger);
|
||||
}
|
||||
} else if (event == XmlPullParser.END_DOCUMENT) {
|
||||
throw new IOException("Premature end of file while parsing triggers");
|
||||
}
|
||||
event = xpp.next();
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void validateRingtones(Context context) {
|
||||
for (ProfileGroup pg : profileGroups.values()) {
|
||||
pg.validateOverrideUris(context);
|
||||
}
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public static Profile fromXml(XmlPullParser xpp, Context context)
|
||||
throws XmlPullParserException, IOException {
|
||||
String value = xpp.getAttributeValue(null, "nameres");
|
||||
int profileNameResId = -1;
|
||||
String profileName = null;
|
||||
|
||||
if (value != null) {
|
||||
profileNameResId = context.getResources().getIdentifier(value, "string", "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("ringModeDescriptor")) {
|
||||
RingModeSettings smd = RingModeSettings.fromXml(xpp, context);
|
||||
profile.setRingMode(smd);
|
||||
}
|
||||
if (name.equals("airplaneModeDescriptor")) {
|
||||
AirplaneModeSettings amd = AirplaneModeSettings.fromXml(xpp, context);
|
||||
profile.setAirplaneMode(amd);
|
||||
}
|
||||
if (name.equals("brightnessDescriptor")) {
|
||||
BrightnessSettings bd = BrightnessSettings.fromXml(xpp, context);
|
||||
profile.setBrightness(bd);
|
||||
}
|
||||
if (name.equals("screen-lock-mode")) {
|
||||
profile.setScreenLockMode(Integer.valueOf(xpp.nextText()));
|
||||
}
|
||||
if (name.equals("expanded-desktop-mode")) {
|
||||
profile.setExpandedDesktopMode(Integer.valueOf(xpp.nextText()));
|
||||
}
|
||||
if (name.equals("doze-mode")) {
|
||||
profile.setDozeMode(Integer.valueOf(xpp.nextText()));
|
||||
}
|
||||
if (name.equals("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("triggers")) {
|
||||
readTriggersFromXml(xpp, context, profile);
|
||||
}
|
||||
} else if (event == XmlPullParser.END_DOCUMENT) {
|
||||
throw new IOException("Premature end of file while parsing profle:" + profileName);
|
||||
}
|
||||
event = xpp.next();
|
||||
}
|
||||
|
||||
/* we just loaded from XML, so nothing needs saving */
|
||||
profile.mDirty = false;
|
||||
|
||||
return profile;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public void doSelect(Context context) {
|
||||
// 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 ring mode
|
||||
mRingMode.processOverride(context);
|
||||
// Set airplane mode
|
||||
mAirplaneMode.processOverride(context);
|
||||
|
||||
// Set brightness
|
||||
mBrightness.processOverride(context);
|
||||
|
||||
// Set expanded desktop
|
||||
// if (mExpandedDesktopMode != ExpandedDesktopMode.DEFAULT) {
|
||||
// Settings.System.putIntForUser(context.getContentResolver(),
|
||||
// Settings.System.EXPANDED_DESKTOP_STATE,
|
||||
// mExpandedDesktopMode == ExpandedDesktopMode.ENABLE ? 1 : 0,
|
||||
// UserHandle.USER_CURRENT);
|
||||
// }
|
||||
|
||||
// Set doze mode
|
||||
if (mDozeMode != DozeMode.DEFAULT) {
|
||||
Settings.Secure.putIntForUser(context.getContentResolver(),
|
||||
Settings.Secure.DOZE_ENABLED,
|
||||
mDozeMode == DozeMode.ENABLE ? 1 : 0,
|
||||
UserHandle.USER_CURRENT);
|
||||
}
|
||||
}
|
||||
|
||||
/** @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 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();
|
||||
}
|
||||
|
||||
}
|
370
src/java/cyanogenmod/app/ProfileGroup.java
Normal file
370
src/java/cyanogenmod/app/ProfileGroup.java
Normal file
@ -0,0 +1,370 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import android.app.Notification;
|
||||
import android.app.NotificationGroup;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
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 void applyOverridesToNotification(Notification notification) {
|
||||
switch (mSoundMode) {
|
||||
case OVERRIDE:
|
||||
notification.sound = mSoundOverride;
|
||||
break;
|
||||
case SUPPRESS:
|
||||
notification.defaults &= ~Notification.DEFAULT_SOUND;
|
||||
notification.sound = null;
|
||||
break;
|
||||
case DEFAULT:
|
||||
break;
|
||||
}
|
||||
switch (mVibrateMode) {
|
||||
case OVERRIDE:
|
||||
notification.defaults |= Notification.DEFAULT_VIBRATE;
|
||||
break;
|
||||
case SUPPRESS:
|
||||
notification.defaults &= ~Notification.DEFAULT_VIBRATE;
|
||||
notification.vibrate = null;
|
||||
break;
|
||||
case DEFAULT:
|
||||
break;
|
||||
}
|
||||
switch (mLightsMode) {
|
||||
case OVERRIDE:
|
||||
notification.defaults |= Notification.DEFAULT_LIGHTS;
|
||||
break;
|
||||
case SUPPRESS:
|
||||
notification.defaults &= ~Notification.DEFAULT_LIGHTS;
|
||||
notification.flags &= ~Notification.FLAG_SHOW_LIGHTS;
|
||||
break;
|
||||
case DEFAULT:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private boolean validateOverrideUri(Context context, Uri uri) {
|
||||
if (RingtoneManager.isDefault(uri)) {
|
||||
return true;
|
||||
}
|
||||
Cursor cursor = context.getContentResolver().query(uri, null, null, null, null);
|
||||
boolean valid = false;
|
||||
|
||||
if (cursor != null) {
|
||||
valid = cursor.moveToFirst();
|
||||
cursor.close();
|
||||
}
|
||||
return valid;
|
||||
}
|
||||
|
||||
void validateOverrideUris(Context context) {
|
||||
if (!validateOverrideUri(context, mSoundOverride)) {
|
||||
mSoundOverride = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
|
||||
mSoundMode = Mode.DEFAULT;
|
||||
mDirty = true;
|
||||
}
|
||||
if (!validateOverrideUri(context, mRingerOverride)) {
|
||||
mRingerOverride = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE);
|
||||
mRingerMode = Mode.DEFAULT;
|
||||
mDirty = true;
|
||||
}
|
||||
}
|
||||
|
||||
/** @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()));
|
||||
}
|
||||
} else if (event == XmlPullParser.END_DOCUMENT) {
|
||||
throw new IOException("Premature end of file while parsing profleGroup:" + name);
|
||||
}
|
||||
event = xpp.next();
|
||||
}
|
||||
|
||||
/* we just loaded from XML, no need to save */
|
||||
profileGroup.mDirty = false;
|
||||
|
||||
return profileGroup;
|
||||
}
|
||||
}
|
467
src/java/cyanogenmod/app/ProfileManager.java
Normal file
467
src/java/cyanogenmod/app/ProfileManager.java
Normal file
@ -0,0 +1,467 @@
|
||||
/*
|
||||
* Copyright (C) 2014 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import android.annotation.SdkConstant;
|
||||
import android.annotation.SdkConstant.SdkConstantType;
|
||||
import android.app.NotificationGroup;
|
||||
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.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import cyanogenmod.app.IProfileManager;
|
||||
|
||||
import com.android.internal.R;
|
||||
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ProfileManager {
|
||||
|
||||
private static IProfileManager sService;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private static final String TAG = "ProfileManager";
|
||||
|
||||
private static final String SYSTEM_PROFILES_ENABLED = "system_profiles_enabled";
|
||||
|
||||
/**
|
||||
* <p>Broadcast Action: A new profile has been selected. This can be triggered by the user
|
||||
* or by calls to the ProfileManagerService / Profile.</p>
|
||||
* @hide
|
||||
*/
|
||||
public static final String INTENT_ACTION_PROFILE_SELECTED =
|
||||
"android.intent.action.PROFILE_SELECTED";
|
||||
|
||||
/**
|
||||
* Extra for {@link INTENT_ACTION_PROFILE_SELECTED} and {@link INTENT_ACTION_PROFILE_UPDATED}:
|
||||
* The name of the newly activated or updated profile
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILE_NAME = "name";
|
||||
|
||||
/**
|
||||
* Extra for {@link INTENT_ACTION_PROFILE_SELECTED} and {@link INTENT_ACTION_PROFILE_UPDATED}:
|
||||
* The string representation of the UUID of the newly activated or updated profile
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILE_UUID = "uuid";
|
||||
|
||||
/**
|
||||
* Extra for {@link INTENT_ACTION_PROFILE_SELECTED}:
|
||||
* The name of the previously active profile
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_LAST_PROFILE_NAME = "lastName";
|
||||
|
||||
/**
|
||||
* Extra for {@link INTENT_ACTION_PROFILE_SELECTED}:
|
||||
* The string representation of the UUID of the previously active profile
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_LAST_PROFILE_UUID = "uuid";
|
||||
|
||||
/**
|
||||
* <p>Broadcast Action: Current profile has been updated. This is triggered every time the
|
||||
* currently active profile is updated, instead of selected.</p>
|
||||
* <p> For instance, this includes profile updates caused by a locale change, which doesn't
|
||||
* trigger a profile selection, but causes its name to change.</p>
|
||||
* @hide
|
||||
*/
|
||||
public static final String INTENT_ACTION_PROFILE_UPDATED =
|
||||
"android.intent.action.PROFILE_UPDATED";
|
||||
|
||||
/**
|
||||
* Activity Action: Shows a profile picker.
|
||||
* <p>
|
||||
* Input: {@link #EXTRA_PROFILE_EXISTING_UUID}, {@link #EXTRA_PROFILE_SHOW_NONE},
|
||||
* {@link #EXTRA_PROFILE_TITLE}.
|
||||
* <p>
|
||||
* Output: {@link #EXTRA_PROFILE_PICKED_UUID}.
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
|
||||
public static final String ACTION_PROFILE_PICKER = "android.intent.action.PROFILE_PICKER";
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public static final UUID NO_PROFILE =
|
||||
UUID.fromString("00000000-0000-0000-0000-000000000000");
|
||||
|
||||
/**
|
||||
* Given to the profile picker as a boolean. Whether to show an item for
|
||||
* deselect the profile. If the "None" item is picked,
|
||||
* {@link #EXTRA_PROFILE_PICKED_UUID} will be {@link #NO_PROFILE}.
|
||||
*
|
||||
* @see #ACTION_PROFILE_PICKER
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILE_SHOW_NONE =
|
||||
"android.intent.extra.profile.SHOW_NONE";
|
||||
|
||||
/**
|
||||
* Given to the profile picker as a {@link UUID} string representation. The {@link UUID}
|
||||
* representation of the current profile, which will be used to show a checkmark next to
|
||||
* the item for this {@link UUID}. If the item is {@link #NO_PROFILE} then "None" item
|
||||
* is selected if {@link EXTRA_PROFILE_SHOW_NONE} is enabled. Otherwise, the current
|
||||
* profile is selected.
|
||||
*
|
||||
* @see #ACTION_PROFILE_PICKER
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILE_EXISTING_UUID =
|
||||
"android.intent.extra.profile.EXISTING_UUID";
|
||||
|
||||
/**
|
||||
* Given to the profile picker as a {@link CharSequence}. The title to
|
||||
* show for the profile picker. This has a default value that is suitable
|
||||
* in most cases.
|
||||
*
|
||||
* @see #ACTION_PROFILE_PICKER
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILE_TITLE = "android.intent.extra.profile.TITLE";
|
||||
|
||||
/**
|
||||
* Returned from the profile picker as a {@link UUID} string representation.
|
||||
* <p>
|
||||
* It will be one of:
|
||||
* <li> the picked profile,
|
||||
* <li> null if the "None" item was picked.
|
||||
*
|
||||
* @see #ACTION_PROFILE_PICKER
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILE_PICKED_UUID =
|
||||
"android.intent.extra.profile.PICKED_UUID";
|
||||
|
||||
|
||||
/**
|
||||
* Broadcast intent action indicating that Profiles has been enabled or disabled.
|
||||
* One extra provides this state as an int.
|
||||
*
|
||||
* @see #EXTRA_PROFILES_STATE
|
||||
* @hide
|
||||
*/
|
||||
@SdkConstant(SdkConstantType.BROADCAST_INTENT_ACTION)
|
||||
public static final String PROFILES_STATE_CHANGED_ACTION =
|
||||
"android.app.profiles.PROFILES_STATE_CHANGED";
|
||||
/**
|
||||
* The lookup key for an int that indicates whether Profiles are enabled or
|
||||
* disabled. Retrieve it with {@link android.content.Intent#getIntExtra(String,int)}.
|
||||
*
|
||||
* @see #PROFILES_STATE_DISABLED
|
||||
* @see #PROFILES_STATE_ENABLED
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILES_STATE = "profile_state";
|
||||
|
||||
/**
|
||||
* Set the resource id theme to use for the dialog picker activity.<br/>
|
||||
* The default theme is <code>com.android.internal.R.Theme_Holo_Dialog_Alert</code>.
|
||||
*
|
||||
* @see #ACTION_PROFILE_PICKER
|
||||
* @hide
|
||||
*/
|
||||
public static final String EXTRA_PROFILE_DIALOG_THEME =
|
||||
"android.intent.extra.profile.DIALOG_THEME";
|
||||
|
||||
/**
|
||||
* Profiles are disabled.
|
||||
*
|
||||
* @see #PROFILES_STATE_CHANGED_ACTION
|
||||
* @hide
|
||||
*/
|
||||
public static final int PROFILES_STATE_DISABLED = 0;
|
||||
/**
|
||||
* Profiles are enabled.
|
||||
*
|
||||
* @see #PROFILES_STATE_CHANGED_ACTION
|
||||
* @hide
|
||||
*/
|
||||
public static final int PROFILES_STATE_ENABLED = 1;
|
||||
|
||||
// A blank profile that is created to be returned if profiles disabled
|
||||
private static Profile mEmptyProfile;
|
||||
|
||||
private static ProfileManager sProfileManagerInstance;
|
||||
private ProfileManager(Context context) {
|
||||
Context appContext = context.getApplicationContext();
|
||||
if (appContext != null) {
|
||||
mContext = appContext;
|
||||
} else {
|
||||
mContext = context;
|
||||
}
|
||||
sService = getService();
|
||||
mEmptyProfile = new Profile("EmptyProfile");
|
||||
}
|
||||
|
||||
/**
|
||||
* Get or create an instance of the {@link cyanogenmod.app.ProfileManager}
|
||||
* @param context
|
||||
* @return {@link cyanogenmod.app.ProfileManager}
|
||||
*/
|
||||
public static ProfileManager getInstance(Context context) {
|
||||
if (sProfileManagerInstance == null) {
|
||||
sProfileManagerInstance = new ProfileManager(context);
|
||||
}
|
||||
return sProfileManagerInstance;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
static public IProfileManager getService() {
|
||||
if (sService != null) {
|
||||
return sService;
|
||||
}
|
||||
IBinder b = ServiceManager.getService(CMContextConstants.CM_PROFILE_SERVICE);
|
||||
sService = IProfileManager.Stub.asInterface(b);
|
||||
return sService;
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void setActiveProfile(String profileName) {
|
||||
if (Settings.System.getInt(mContext.getContentResolver(),
|
||||
SYSTEM_PROFILES_ENABLED, 1) == 1) {
|
||||
// Profiles are enabled, return active profile
|
||||
try {
|
||||
getService().setActiveProfileByName(profileName);
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setActiveProfile(UUID profileUuid) {
|
||||
if (Settings.System.getInt(mContext.getContentResolver(),
|
||||
SYSTEM_PROFILES_ENABLED, 1) == 1) {
|
||||
// Profiles are enabled, return active profile
|
||||
try {
|
||||
getService().setActiveProfile(new ParcelUuid(profileUuid));
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getLocalizedMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Profile getActiveProfile() {
|
||||
if (Settings.System.getInt(mContext.getContentResolver(),
|
||||
SYSTEM_PROFILES_ENABLED, 1) == 1) {
|
||||
// Profiles are enabled, return active profile
|
||||
try {
|
||||
return getService().getActiveProfile();
|
||||
} catch (RemoteException e) {
|
||||
Log.e(TAG, e.getLocalizedMessage(), e);
|
||||
}
|
||||
return null;
|
||||
|
||||
} else {
|
||||
// Profiles are not enabled, return the empty profile
|
||||
return mEmptyProfile;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** @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);
|
||||
}
|
||||
}
|
||||
}
|
144
src/java/cyanogenmod/app/ProfileTriggerHelper.java
Normal file
144
src/java/cyanogenmod/app/ProfileTriggerHelper.java
Normal file
@ -0,0 +1,144 @@
|
||||
/*
|
||||
* Copyright (c) 2013-2014 The CyanogenMod Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package cyanogenmod.app;
|
||||
|
||||
import android.bluetooth.BluetoothDevice;
|
||||
import android.content.BroadcastReceiver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.database.ContentObserver;
|
||||
import android.net.wifi.WifiManager;
|
||||
import android.net.wifi.WifiSsid;
|
||||
import android.net.wifi.WifiInfo;
|
||||
import android.os.Handler;
|
||||
import android.provider.Settings;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ProfileTriggerHelper extends BroadcastReceiver {
|
||||
private static final String TAG = "ProfileTriggerHelper";
|
||||
|
||||
private Context mContext;
|
||||
private ProfileManager mManager;
|
||||
|
||||
private WifiManager mWifiManager;
|
||||
private String mLastConnectedSSID;
|
||||
|
||||
private IntentFilter mIntentFilter;
|
||||
private boolean mFilterRegistered = false;
|
||||
|
||||
private ContentObserver mSettingsObserver = new ContentObserver(new Handler()) {
|
||||
@Override
|
||||
public void onChange(boolean selfChange) {
|
||||
updateEnabled();
|
||||
}
|
||||
};
|
||||
|
||||
public ProfileTriggerHelper(Context context, ProfileManager manager) {
|
||||
mContext = context;
|
||||
mManager = manager;
|
||||
|
||||
mWifiManager = (WifiManager) mContext.getSystemService(Context.WIFI_SERVICE);
|
||||
mLastConnectedSSID = getActiveSSID();
|
||||
|
||||
mIntentFilter = new IntentFilter();
|
||||
mIntentFilter.addAction(WifiManager.NETWORK_STATE_CHANGED_ACTION);
|
||||
mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_CONNECTED);
|
||||
mIntentFilter.addAction(BluetoothDevice.ACTION_ACL_DISCONNECTED);
|
||||
// mIntentFilter.addAction(AudioManager.A2DP_ROUTE_CHANGED_ACTION);
|
||||
updateEnabled();
|
||||
|
||||
mContext.getContentResolver().registerContentObserver(
|
||||
Settings.System.getUriFor(Settings.System.SYSTEM_PROFILES_ENABLED), false,
|
||||
mSettingsObserver);
|
||||
}
|
||||
|
||||
public void updateEnabled() {
|
||||
boolean enabled = Settings.System.getInt(mContext.getContentResolver(),
|
||||
Settings.System.SYSTEM_PROFILES_ENABLED, 1) == 1;
|
||||
if (enabled && !mFilterRegistered) {
|
||||
Log.v(TAG, "Enabling");
|
||||
mContext.registerReceiver(this, mIntentFilter);
|
||||
mFilterRegistered = true;
|
||||
} else if (!enabled && mFilterRegistered) {
|
||||
Log.v(TAG, "Disabling");
|
||||
mContext.unregisterReceiver(this);
|
||||
mFilterRegistered = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
String action = intent.getAction();
|
||||
|
||||
if (action.equals(WifiManager.NETWORK_STATE_CHANGED_ACTION)) {
|
||||
String activeSSID = getActiveSSID();
|
||||
int triggerState;
|
||||
|
||||
if (activeSSID != null) {
|
||||
triggerState = Profile.TriggerState.ON_CONNECT;
|
||||
mLastConnectedSSID = activeSSID;
|
||||
} else {
|
||||
triggerState = Profile.TriggerState.ON_DISCONNECT;
|
||||
}
|
||||
checkTriggers(Profile.TriggerType.WIFI, mLastConnectedSSID, triggerState);
|
||||
} else if (action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)
|
||||
|| action.equals(BluetoothDevice.ACTION_ACL_DISCONNECTED)) {
|
||||
int triggerState = action.equals(BluetoothDevice.ACTION_ACL_CONNECTED)
|
||||
? Profile.TriggerState.ON_CONNECT : Profile.TriggerState.ON_DISCONNECT;
|
||||
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
|
||||
checkTriggers(Profile.TriggerType.BLUETOOTH, device.getAddress(), triggerState);
|
||||
/* } else if (action.equals(AudioManager.A2DP_ROUTE_CHANGED_ACTION)) {
|
||||
BluetoothDevice device = intent
|
||||
.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
|
||||
int state = intent.getIntExtra(BluetoothProfile.EXTRA_STATE, 0);
|
||||
int triggerState = (state == BluetoothProfile.STATE_CONNECTED)
|
||||
? Profile.TriggerState.ON_A2DP_CONNECT :
|
||||
Profile.TriggerState.ON_A2DP_DISCONNECT;
|
||||
|
||||
checkTriggers(Profile.TriggerType.BLUETOOTH, device.getAddress(), triggerState);*/
|
||||
}
|
||||
}
|
||||
|
||||
private void checkTriggers(int type, String id, int newState) {
|
||||
/*for (Profile p : mManager.getProfileList()) {
|
||||
if (newState != p.getTrigger(type, id)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
UUID currentProfileUuid = mManager.getActiveProfile().getUuid();
|
||||
if (!currentProfileUuid.equals(p.getUuid())) {
|
||||
//mManager.setActiveProfile(p, true);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
private String getActiveSSID() {
|
||||
WifiInfo wifiinfo = mWifiManager.getConnectionInfo();
|
||||
if (wifiinfo == null) {
|
||||
return null;
|
||||
}
|
||||
WifiSsid ssid = wifiinfo.getWifiSsid();
|
||||
if (ssid == null) {
|
||||
return null;
|
||||
}
|
||||
return ssid.toString();
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user