cmsdk: Add constraints and behaviors for our preferences

* Add a new set of attributes which can be declared in the
   preference XML which will cause the preference to be
   removed from the hierarchy if the constraint is not met.
   Currently we can check for installed packages, system
   properties, config references, and system features.
 * CMPartsPreference is also updated to use similar logic
   based on the external XML.

Change-Id: If8fb39cd3312623e38bb3498bfb3f29ed8b444d6
This commit is contained in:
Steve Kondik
2016-09-15 05:16:42 -07:00
parent 9faa2740a5
commit 2d61e0ceba
16 changed files with 456 additions and 25 deletions

View File

@@ -737,6 +737,10 @@ package cyanogenmod.platform {
public static final class R.attr {
ctor public R.attr();
field public static final int requiresConfig = 1057030148; // 0x3f010004
field public static final int requiresFeature = 1057030147; // 0x3f010003
field public static final int requiresPackage = 1057030146; // 0x3f010002
field public static final int requiresProperty = 1057030149; // 0x3f010005
}
public static final class R.bool {
@@ -747,6 +751,10 @@ package cyanogenmod.platform {
ctor public R.drawable();
}
public static final class R.id {
ctor public R.id();
}
public static final class R.integer {
ctor public R.integer();
}
@@ -782,7 +790,7 @@ package cyanogenmod.power {
package cyanogenmod.preference {
public class CMGlobalSettingSwitchPreference extends SwitchPreference {
public class CMGlobalSettingSwitchPreference extends cyanogenmod.preference.SelfRemovingSwitchPreference {
ctor public CMGlobalSettingSwitchPreference(android.content.Context, android.util.AttributeSet, int);
ctor public CMGlobalSettingSwitchPreference(android.content.Context, android.util.AttributeSet);
ctor public CMGlobalSettingSwitchPreference(android.content.Context);
@@ -791,7 +799,7 @@ package cyanogenmod.preference {
method protected boolean persistBoolean(boolean);
}
public class CMSecureSettingListPreference extends ListPreference {
public class CMSecureSettingListPreference extends cyanogenmod.preference.SelfRemovingListPreference {
ctor public CMSecureSettingListPreference(android.content.Context, android.util.AttributeSet, int);
ctor public CMSecureSettingListPreference(android.content.Context, android.util.AttributeSet);
method public int getIntValue(int);
@@ -800,7 +808,7 @@ package cyanogenmod.preference {
method protected boolean persistString(java.lang.String);
}
public class CMSecureSettingSwitchPreference extends SwitchPreference {
public class CMSecureSettingSwitchPreference extends cyanogenmod.preference.SelfRemovingSwitchPreference {
ctor public CMSecureSettingSwitchPreference(android.content.Context, android.util.AttributeSet, int);
ctor public CMSecureSettingSwitchPreference(android.content.Context, android.util.AttributeSet);
ctor public CMSecureSettingSwitchPreference(android.content.Context);
@@ -809,7 +817,7 @@ package cyanogenmod.preference {
method protected boolean persistBoolean(boolean);
}
public class CMSystemSettingListPreference extends ListPreference {
public class CMSystemSettingListPreference extends cyanogenmod.preference.SelfRemovingListPreference {
ctor public CMSystemSettingListPreference(android.content.Context, android.util.AttributeSet, int);
ctor public CMSystemSettingListPreference(android.content.Context, android.util.AttributeSet);
method public int getIntValue(int);
@@ -818,7 +826,7 @@ package cyanogenmod.preference {
method protected boolean persistString(java.lang.String);
}
public class CMSystemSettingSwitchPreference extends SwitchPreference {
public class CMSystemSettingSwitchPreference extends cyanogenmod.preference.SelfRemovingSwitchPreference {
ctor public CMSystemSettingSwitchPreference(android.content.Context, android.util.AttributeSet, int);
ctor public CMSystemSettingSwitchPreference(android.content.Context, android.util.AttributeSet);
ctor public CMSystemSettingSwitchPreference(android.content.Context);
@@ -827,7 +835,41 @@ package cyanogenmod.preference {
method protected boolean persistBoolean(boolean);
}
public class SystemSettingSwitchPreference extends SwitchPreference {
public class ConstraintsHelper {
ctor public ConstraintsHelper(android.content.Context, android.util.AttributeSet, Preference);
method public void applyConstraints();
method public static boolean hasSystemFeature(android.content.Context, java.lang.String);
method public static boolean isDozeAvailable(android.content.Context);
method public static boolean isPackageInstalled(android.content.Context, java.lang.String, boolean);
method public static boolean isVoiceCapable(android.content.Context);
method public void setAvailable(boolean);
}
public class SelfRemovingListPreference extends ListPreference {
ctor public SelfRemovingListPreference(android.content.Context, android.util.AttributeSet, int);
ctor public SelfRemovingListPreference(android.content.Context, android.util.AttributeSet);
ctor public SelfRemovingListPreference(android.content.Context);
method public void onBindViewHolder(PreferenceViewHolder);
method protected void setAvailable(boolean);
}
public class SelfRemovingPreference extends Preference {
ctor public SelfRemovingPreference(android.content.Context, android.util.AttributeSet, int);
ctor public SelfRemovingPreference(android.content.Context, android.util.AttributeSet);
ctor public SelfRemovingPreference(android.content.Context);
method public void onBindViewHolder(PreferenceViewHolder);
method protected void setAvailable(boolean);
}
public class SelfRemovingSwitchPreference extends SwitchPreference {
ctor public SelfRemovingSwitchPreference(android.content.Context, android.util.AttributeSet, int);
ctor public SelfRemovingSwitchPreference(android.content.Context, android.util.AttributeSet);
ctor public SelfRemovingSwitchPreference(android.content.Context);
method public void onBindViewHolder(PreferenceViewHolder);
method protected void setAvailable(boolean);
}
public class SystemSettingSwitchPreference extends cyanogenmod.preference.SelfRemovingSwitchPreference {
ctor public SystemSettingSwitchPreference(android.content.Context, android.util.AttributeSet, int);
ctor public SystemSettingSwitchPreference(android.content.Context, android.util.AttributeSet);
ctor public SystemSettingSwitchPreference(android.content.Context);

View File

@@ -22,6 +22,7 @@ LOCAL_CERTIFICATE := platform
LOCAL_AAPT_FLAGS := --auto-add-overlay
LOCAL_AAPT_FLAGS += --private-symbols org.cyanogenmod.platform.internal
LOCAL_RESOURCE_DIR := $(addprefix $(LOCAL_PATH)/, res)
LOCAL_RESOURCE_DIR += $(LOCAL_PATH)/../../sdk/res/res
# Tell aapt to create "extending (non-application)" resource IDs,
# since these resources will be used by many apps.

View File

@@ -14,7 +14,7 @@
See the License for the specific language governing permissions and
limitations under the License.
-->
<resources>
<resources xmlns:cm="http://schemas.android.com/apk/res/cyanogenmod.platform">
<declare-styleable name="LiveLockScreen">
<attr name="settingsActivity" format="string" />
<attr name="type">
@@ -22,4 +22,11 @@
<flag name="event" value="2"/>
</attr>
</declare-styleable>
</resources>
<declare-styleable name="cm:SelfRemovingPreference">
<attr name="requiresPackage" format="string" />
<attr name="requiresFeature" format="string" />
<attr name="requiresConfig" format="string" />
<attr name="requiresProperty" format="string" />
</declare-styleable>
</resources>

View File

@@ -0,0 +1,12 @@
<resources>
<!-- Declared at vendor/cmsdk/cm/res/../../sdk/res/res/values/attrs.xml:27 -->
<public type="attr" name="requiresPackage" id="0x3f010002" />
<!-- Declared at vendor/cmsdk/cm/res/../../sdk/res/res/values/attrs.xml:28 -->
<public type="attr" name="requiresFeature" id="0x3f010003" />
<!-- Declared at vendor/cmsdk/cm/res/../../sdk/res/res/values/attrs.xml:29 -->
<public type="attr" name="requiresConfig" id="0x3f010004" />
<!-- Declared at vendor/cmsdk/cm/res/../../sdk/res/res/values/attrs.xml:30 -->
<public type="attr" name="requiresProperty" id="0x3f010005" />
</resources>

View File

@@ -0,0 +1,8 @@
<resources>
<java-symbol type="attr" name="requiresPackage" />
<java-symbol type="attr" name="requiresFeature" />
<java-symbol type="attr" name="requiresConfig" />
<java-symbol type="attr" name="requiresProperty" />
</resources>

View File

@@ -17,12 +17,12 @@
package cyanogenmod.preference;
import android.content.Context;
import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
import cyanogenmod.providers.CMSettings;
public class CMGlobalSettingSwitchPreference extends SwitchPreference {
public class CMGlobalSettingSwitchPreference extends SelfRemovingSwitchPreference {
public CMGlobalSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@@ -32,7 +32,7 @@ public class CMGlobalSettingSwitchPreference extends SwitchPreference {
}
public CMGlobalSettingSwitchPreference(Context context) {
super(context, null);
super(context);
}
@Override

View File

@@ -16,13 +16,13 @@
package cyanogenmod.preference;
import android.content.Context;
import android.support.v7.preference.ListPreference;
import android.util.AttributeSet;
import cyanogenmod.providers.CMSettings;
public class CMSecureSettingListPreference extends ListPreference {
public class CMSecureSettingListPreference extends SelfRemovingListPreference {
public CMSecureSettingListPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

View File

@@ -17,12 +17,12 @@
package cyanogenmod.preference;
import android.content.Context;
import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
import cyanogenmod.providers.CMSettings;
public class CMSecureSettingSwitchPreference extends SwitchPreference {
public class CMSecureSettingSwitchPreference extends SelfRemovingSwitchPreference {
public CMSecureSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@@ -32,7 +32,7 @@ public class CMSecureSettingSwitchPreference extends SwitchPreference {
}
public CMSecureSettingSwitchPreference(Context context) {
super(context, null);
super(context);
}
@Override

View File

@@ -16,13 +16,12 @@
package cyanogenmod.preference;
import android.content.Context;
import android.support.v7.preference.ListPreference;
import android.util.AttributeSet;
import cyanogenmod.providers.CMSettings;
public class CMSystemSettingListPreference extends ListPreference {
public class CMSystemSettingListPreference extends SelfRemovingListPreference {
public CMSystemSettingListPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

View File

@@ -17,12 +17,12 @@
package cyanogenmod.preference;
import android.content.Context;
import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
import cyanogenmod.providers.CMSettings;
public class CMSystemSettingSwitchPreference extends SwitchPreference {
public class CMSystemSettingSwitchPreference extends SelfRemovingSwitchPreference {
public CMSystemSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@@ -32,7 +32,7 @@ public class CMSystemSettingSwitchPreference extends SwitchPreference {
}
public CMSystemSettingSwitchPreference(Context context) {
super(context, null);
super(context);
}
@Override

View File

@@ -0,0 +1,196 @@
/*
* Copyright (C) 2016 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.preference;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.TypedArray;
import android.os.Build;
import android.os.SystemProperties;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceGroup;
import android.telephony.TelephonyManager;
import android.text.TextUtils;
import android.util.AttributeSet;
import android.util.TypedValue;
import cyanogenmod.platform.R;
/**
* Helpers for checking if a device supports various features.
*/
public class ConstraintsHelper {
private static final String TAG = "Constraints";
private final Context mContext;
private final AttributeSet mAttrs;
private final Preference mPref;
private boolean mAvailable = true;
public ConstraintsHelper(Context context, AttributeSet attrs, Preference pref) {
mContext = context;
mAttrs = attrs;
mPref = pref;
mAvailable = checkConstraints();
}
public void setAvailable(boolean available) {
mAvailable = available;
}
public void applyConstraints() {
if (!mAvailable) {
final PreferenceGroup group = getParent(mPref);
group.removePreference(mPref);
if (group.getPreferenceCount() == 0) {
getParent(group).removePreference(group);
}
}
}
private PreferenceGroup getParent(Preference preference)
{
return getParent(mPref.getPreferenceManager().getPreferenceScreen(), preference);
}
private PreferenceGroup getParent(PreferenceGroup root, Preference preference)
{
for (int i = 0; i < root.getPreferenceCount(); i++)
{
Preference p = root.getPreference(i);
if (p == preference)
return root;
if (PreferenceGroup.class.isInstance(p))
{
PreferenceGroup parent = getParent((PreferenceGroup)p, preference);
if (parent != null)
return parent;
}
}
return null;
}
private boolean checkConstraints() {
if (mAttrs == null) {
return true;
}
TypedArray a = mContext.getResources().obtainAttributes(mAttrs,
R.styleable.cm_SelfRemovingPreference);
try {
// Check if a specific package is installed
String rPackage = a.getString(R.styleable.cm_SelfRemovingPreference_requiresPackage);
if (rPackage != null && !isPackageInstalled(mContext, rPackage, false)) {
return false;
}
// Check if a system feature is available
String rFeature = a.getString(R.styleable.cm_SelfRemovingPreference_requiresFeature);
if (rFeature != null && !hasSystemFeature(mContext, rFeature)) {
return false;
}
// Check a boolean system property
String rProperty = a.getString(R.styleable.cm_SelfRemovingPreference_requiresProperty);
if (rProperty != null) {
String value = SystemProperties.get(rProperty);
if (value == null || !Boolean.parseBoolean(value)) {
return false;
}
}
// Check a config resource. This can be a bool or a string. A null string
// fails the constraint.
TypedValue tv = a.peekValue(R.styleable.cm_SelfRemovingPreference_requiresConfig);
if (tv != null) {
if (tv.type == TypedValue.TYPE_STRING) {
if (tv.resourceId != 0) {
if (mContext.getResources().getString(tv.resourceId) == null) {
return false;
}
}
} else if (tv.type == TypedValue.TYPE_INT_BOOLEAN) {
if (tv.resourceId != 0) {
if (tv.data == 0) {
return false;
}
}
}
}
} finally {
a.recycle();
}
return true;
}
/**
* Returns whether the device supports a particular feature
*/
public static boolean hasSystemFeature(Context context, String feature) {
return context.getPackageManager().hasSystemFeature(feature);
}
/**
* Returns whether the device is voice-capable (meaning, it is also a phone).
*/
public static boolean isVoiceCapable(Context context) {
TelephonyManager telephony =
(TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
return telephony != null && telephony.isVoiceCapable();
}
/**
* Checks if a package is installed. Set the ignoreState argument to true if you don't
* care if the package is enabled/disabled.
*/
public static boolean isPackageInstalled(Context context, String pkg, boolean ignoreState) {
if (pkg != null) {
try {
PackageInfo pi = context.getPackageManager().getPackageInfo(pkg, 0);
if (!pi.applicationInfo.enabled && !ignoreState) {
return false;
}
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
return true;
}
/**
* Does the device support Doze?
* @param context
* @return
*/
public static boolean isDozeAvailable(Context context) {
String name = Build.IS_DEBUGGABLE ? SystemProperties.get("debug.doze.component") : null;
if (TextUtils.isEmpty(name)) {
name = context.getResources().getString(
com.android.internal.R.string.config_dozeComponent);
}
return !TextUtils.isEmpty(name);
}
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright (C) 2016 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.preference;
import android.content.Context;
import android.support.v7.preference.ListPreference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
public class SelfRemovingListPreference extends ListPreference {
private final ConstraintsHelper mConstraints;
public SelfRemovingListPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mConstraints = new ConstraintsHelper(context, attrs, this);
}
public SelfRemovingListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mConstraints = new ConstraintsHelper(context, attrs, this);
}
public SelfRemovingListPreference(Context context) {
super(context);
mConstraints = new ConstraintsHelper(context, null, this);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mConstraints.applyConstraints();
}
protected void setAvailable(boolean available) {
mConstraints.setAvailable(available);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2016 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.preference;
import android.content.Context;
import android.support.v7.preference.Preference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
/**
* A Preference which can automatically remove itself from the hierarchy
* based on constraints set in XML.
*/
public class SelfRemovingPreference extends Preference {
private final ConstraintsHelper mConstraints;
public SelfRemovingPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mConstraints = new ConstraintsHelper(context, attrs, this);
}
public SelfRemovingPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mConstraints = new ConstraintsHelper(context, attrs, this);
}
public SelfRemovingPreference(Context context) {
super(context);
mConstraints = new ConstraintsHelper(context, null, this);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mConstraints.applyConstraints();
}
protected void setAvailable(boolean available) {
mConstraints.setAvailable(available);
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright (C) 2016 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.preference;
import android.content.Context;
import android.support.v14.preference.SwitchPreference;
import android.support.v7.preference.PreferenceViewHolder;
import android.util.AttributeSet;
/**
* A SwitchPreference which can automatically remove itself from the hierarchy
* based on constraints set in XML.
*/
public class SelfRemovingSwitchPreference extends SwitchPreference {
private final ConstraintsHelper mConstraints;
public SelfRemovingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mConstraints = new ConstraintsHelper(context, attrs, this);
}
public SelfRemovingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mConstraints = new ConstraintsHelper(context, attrs, this);
}
public SelfRemovingSwitchPreference(Context context) {
super(context);
mConstraints = new ConstraintsHelper(context, null, this);
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mConstraints.applyConstraints();
}
protected void setAvailable(boolean available) {
mConstraints.setAvailable(available);
}
}

View File

@@ -18,10 +18,10 @@ package cyanogenmod.preference;
import android.content.Context;
import android.provider.Settings;
import android.support.v14.preference.SwitchPreference;
import android.util.AttributeSet;
public class SystemSettingSwitchPreference extends SwitchPreference {
public class SystemSettingSwitchPreference extends SelfRemovingSwitchPreference {
public SystemSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}

View File

@@ -19,15 +19,16 @@ import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.support.v7.preference.Preference;
import android.util.AttributeSet;
import cyanogenmod.preference.SelfRemovingPreference;
import static org.cyanogenmod.internal.cmparts.PartsList.ACTION_PART;
import static org.cyanogenmod.internal.cmparts.PartsList.ACTION_PART_CHANGED;
import static org.cyanogenmod.internal.cmparts.PartsList.EXTRA_PART;
import static org.cyanogenmod.internal.cmparts.PartsList.EXTRA_PART_KEY;
public class CMPartsPreference extends Preference {
public class CMPartsPreference extends SelfRemovingPreference {
private static final String TAG = "CMPartsPreference";
@@ -41,6 +42,10 @@ public class CMPartsPreference extends Preference {
throw new RuntimeException("Part not found: " + getKey());
}
if (!mPart.isAvailable()) {
setAvailable(false);
}
Intent i = new Intent(ACTION_PART);
i.putExtra(EXTRA_PART_KEY, mPart.getName());
setIntent(i);