sdk: Introduce LineagePreferenceLib

Because of some nested dependency breakage, we can no longer include
Android libraries in main SDK lib, therefore we are moving all
preference related code to a separate package that Settings/LineageParts
will depend on.

Change-Id: Iea379a580a08ea13f71e3503aa096ba0ed7e7cef
This commit is contained in:
LuK1337
2022-08-30 09:24:33 +02:00
parent c2c42fe8d1
commit 514848cd6d
36 changed files with 62 additions and 33 deletions

View File

@@ -1,418 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* 2017,2019-2020 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.TypedArray;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.telephony.TelephonyManager;
import android.util.ArraySet;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.widget.TextView;
import androidx.preference.Preference;
import androidx.preference.PreferenceGroup;
import androidx.preference.PreferenceManager;
import androidx.preference.PreferenceViewHolder;
import java.util.Arrays;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import lineageos.hardware.LineageHardwareManager;
import lineageos.platform.R;
/**
* Helpers for checking if a device supports various features.
*
* @hide
*/
public class ConstraintsHelper {
private static final String TAG = "ConstraintsHelper";
private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
private final Context mContext;
private final AttributeSet mAttrs;
private final Preference mPref;
private boolean mAvailable = true;
private boolean mVerifyIntent = true;
private int mSummaryMinLines = -1;
private String[] mReplacesKey = null;
public ConstraintsHelper(Context context, AttributeSet attrs, Preference pref) {
mContext = context;
mAttrs = attrs;
mPref = pref;
TypedArray a = context.getResources().obtainAttributes(attrs,
R.styleable.lineage_SelfRemovingPreference);
mSummaryMinLines = a.getInteger(R.styleable.lineage_SelfRemovingPreference_minSummaryLines, -1);
String replacesKey = a.getString(R.styleable.lineage_SelfRemovingPreference_replacesKey);
if (replacesKey != null) {
mReplacesKey = replacesKey.split("\\|");
}
setAvailable(checkConstraints());
Log.d(TAG, "construct key=" + mPref.getKey() + " available=" + mAvailable);
}
public void setAvailable(boolean available) {
mAvailable = available;
if (!available) {
Graveyard.get(mContext).addTombstone(mPref.getKey());
}
}
public boolean isAvailable() {
return mAvailable;
}
public void setVerifyIntent(boolean verifyIntent) {
mVerifyIntent = verifyIntent;
}
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 isNegated(String key) {
return key != null && key.startsWith("!");
}
private void checkIntent() {
Intent i = mPref.getIntent();
if (i != null) {
if (!resolveIntent(mContext, i)) {
Graveyard.get(mContext).addTombstone(mPref.getKey());
mAvailable = false;
}
}
}
private boolean checkConstraints() {
if (mAttrs == null) {
return true;
}
TypedArray a = mContext.getResources().obtainAttributes(mAttrs,
R.styleable.lineage_SelfRemovingPreference);
try {
// Check if the current user is an owner
boolean rOwner = a.getBoolean(R.styleable.lineage_SelfRemovingPreference_requiresOwner, false);
if (rOwner && UserHandle.myUserId() != UserHandle.USER_SYSTEM) {
return false;
}
// Check if a specific package is installed
String rPackage = a.getString(R.styleable.lineage_SelfRemovingPreference_requiresPackage);
if (rPackage != null) {
boolean negated = isNegated(rPackage);
if (negated) {
rPackage = rPackage.substring(1);
}
boolean available = isPackageInstalled(mContext, rPackage, false);
if (available == negated) {
return false;
}
}
// Check if an intent can be resolved to handle the given action
String rAction = a.getString(R.styleable.lineage_SelfRemovingPreference_requiresAction);
if (rAction != null) {
boolean negated = isNegated(rAction);
if (negated) {
rAction = rAction.substring(1);
}
boolean available = resolveIntent(mContext, rAction);
if (available == negated) {
return false;
}
}
// Check if a system feature is available
String rFeature = a.getString(R.styleable.lineage_SelfRemovingPreference_requiresFeature);
if (rFeature != null) {
boolean negated = isNegated(rFeature);
if (negated) {
rFeature = rFeature.substring(1);
}
boolean available = rFeature.startsWith("lineagehardware:") ?
LineageHardwareManager.getInstance(mContext).isSupported(
rFeature.substring("lineagehardware:".length())) :
hasSystemFeature(mContext, rFeature);
if (available == negated) {
return false;
}
}
// Check a boolean system property
String rProperty = a.getString(R.styleable.lineage_SelfRemovingPreference_requiresProperty);
if (rProperty != null) {
boolean negated = isNegated(rProperty);
if (negated) {
rProperty = rProperty.substring(1);
}
String value = SystemProperties.get(rProperty);
boolean available = value != null && Boolean.parseBoolean(value);
if (available == negated) {
return false;
}
}
// Check a config resource. This can be a bool, string or integer.
// The preference is removed if any of the following are true:
// * A bool resource is false.
// * A string resource is null.
// * An integer resource is zero.
// * An integer is non-zero and when bitwise logically ANDed with
// attribute requiresConfigMask, the result is zero.
TypedValue tv = a.peekValue(R.styleable.lineage_SelfRemovingPreference_requiresConfig);
if (tv != null && tv.resourceId != 0) {
if (tv.type == TypedValue.TYPE_STRING &&
mContext.getResources().getString(tv.resourceId) == null) {
return false;
} else if (tv.type == TypedValue.TYPE_INT_BOOLEAN && tv.data == 0) {
return false;
} else if (tv.type == TypedValue.TYPE_INT_DEC) {
int mask = a.getInt(
R.styleable.lineage_SelfRemovingPreference_requiresConfigMask, -1);
if (tv.data == 0 || (mask >= 0 && (tv.data & mask) == 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;
}
/**
* Checks if a package is available to handle the given action.
*/
public static boolean resolveIntent(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "resolveIntent " + Objects.toString(intent));
// check whether the target handler exist in system
PackageManager pm = context.getPackageManager();
List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(intent,
PackageManager.MATCH_SYSTEM_ONLY,
UserHandle.myUserId());
for (ResolveInfo resolveInfo : results) {
// check is it installed in system.img, exclude the application
// installed by user
if (DEBUG) Log.d(TAG, "resolveInfo: " + Objects.toString(resolveInfo));
if ((resolveInfo.activityInfo.applicationInfo.flags &
ApplicationInfo.FLAG_SYSTEM) != 0) {
return true;
}
}
return false;
}
public static boolean resolveIntent(Context context, String action) {
return resolveIntent(context, new Intent(action));
}
public static int getAttr(Context context, int attr, int fallbackAttr) {
TypedValue value = new TypedValue();
context.getTheme().resolveAttribute(attr, value, true);
if (value.resourceId != 0) {
return attr;
}
return fallbackAttr;
}
public void onAttached() {
checkIntent();
if (isAvailable() && mReplacesKey != null) {
Graveyard.get(mContext).addTombstones(mReplacesKey);
}
Graveyard.get(mContext).summonReaper(mPref.getPreferenceManager());
}
public void onBindViewHolder(PreferenceViewHolder holder) {
if (!isAvailable()) {
return;
}
if (mSummaryMinLines > 0) {
TextView textView = (TextView) holder.itemView.findViewById(android.R.id.summary);
if (textView != null) {
textView.setMinLines(mSummaryMinLines);
}
}
}
/**
* If we want to keep this at the preference level vs the fragment level, we need to
* collate all the preferences that need to be removed when attached to the
* hierarchy, then purge them all when loading is complete. The Graveyard keeps track
* of this, and will reap the dead when onAttached is called.
*/
private static class Graveyard {
private Set<String> mDeathRow = new ArraySet<>();
private static Graveyard sInstance;
private final Context mContext;
private Graveyard(Context context) {
mContext = context;
}
public synchronized static Graveyard get(Context context) {
if (sInstance == null) {
sInstance = new Graveyard(context);
}
return sInstance;
}
public void addTombstone(String pref) {
synchronized (mDeathRow) {
mDeathRow.add(pref);
}
}
public void addTombstones(String[] prefs) {
synchronized (mDeathRow) {
mDeathRow.addAll(Arrays.asList(prefs));
}
}
private PreferenceGroup getParent(Preference p1, Preference p2) {
return getParent(p1.getPreferenceManager().getPreferenceScreen(), p2);
}
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 void hidePreference(PreferenceManager mgr, Preference pref) {
pref.setVisible(false);
// Hide the group if nothing is visible
final PreferenceGroup group = getParent(pref, pref);
boolean allHidden = true;
for (int i = 0; i < group.getPreferenceCount(); i++) {
if (group.getPreference(i).isVisible()) {
allHidden = false;
break;
}
}
if (allHidden) {
group.setVisible(false);
}
}
public void summonReaper(PreferenceManager mgr) {
synchronized (mDeathRow) {
Set<String> notReadyForReap = new ArraySet<>();
for (String dead : mDeathRow) {
Preference deadPref = mgr.findPreference(dead);
if (deadPref != null) {
hidePreference(mgr, deadPref);
} else {
notReadyForReap.add(dead);
}
}
mDeathRow = notReadyForReap;
}
}
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2021 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
import androidx.preference.PreferenceDataStore;
import com.android.settingslib.widget.MainSwitchPreference;
public class GlobalSettingMainSwitchPreference extends MainSwitchPreference {
public GlobalSettingMainSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setPreferenceDataStore(new DataStore());
}
public GlobalSettingMainSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPreferenceDataStore(new DataStore());
}
public GlobalSettingMainSwitchPreference(Context context) {
super(context, null);
setPreferenceDataStore(new DataStore());
}
private class DataStore extends PreferenceDataStore {
@Override
public void putBoolean(String key, boolean value) {
Settings.Global.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return Settings.Global.getInt(getContext().getContentResolver(), key,
defaultValue ? 1 : 0) != 0;
}
}
}

View File

@@ -1,53 +0,0 @@
/**
* Copyright (C) 2014-2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
public class GlobalSettingSwitchPreference extends SelfRemovingSwitchPreference {
public GlobalSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public GlobalSettingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public GlobalSettingSwitchPreference(Context context) {
super(context, null);
}
@Override
protected boolean isPersisted() {
return Settings.Global.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putBoolean(String key, boolean value) {
Settings.Global.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
protected boolean getBoolean(String key, boolean defaultValue) {
return Settings.Global.getInt(getContext().getContentResolver(),
key, defaultValue ? 1 : 0) != 0;
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2022 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import lineageos.providers.LineageSettings;
public class LineageGlobalSettingListPreference extends SelfRemovingListPreference {
public LineageGlobalSettingListPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LineageGlobalSettingListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public int getIntValue(int defValue) {
return getValue() == null ? defValue : Integer.valueOf(getValue());
}
@Override
protected boolean isPersisted() {
return LineageSettings.Global.getString(getContext().getContentResolver(),
getKey()) != null;
}
@Override
protected void putString(String key, String value) {
LineageSettings.Global.putString(getContext().getContentResolver(), key, value);
}
@Override
protected String getString(String key, String defaultValue) {
return LineageSettings.Global.getString(getContext().getContentResolver(),
key, defaultValue);
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright (C) 2021 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.PreferenceDataStore;
import com.android.settingslib.widget.MainSwitchPreference;
import lineageos.providers.LineageSettings;
public class LineageGlobalSettingMainSwitchPreference extends MainSwitchPreference {
public LineageGlobalSettingMainSwitchPreference(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setPreferenceDataStore(new DataStore());
}
public LineageGlobalSettingMainSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPreferenceDataStore(new DataStore());
}
public LineageGlobalSettingMainSwitchPreference(Context context) {
super(context);
setPreferenceDataStore(new DataStore());
}
private class DataStore extends PreferenceDataStore {
@Override
public void putBoolean(String key, boolean value) {
LineageSettings.Global.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return LineageSettings.Global.getInt(getContext().getContentResolver(), key,
defaultValue ? 1 : 0) != 0;
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import lineageos.providers.LineageSettings;
public class LineageGlobalSettingSwitchPreference extends SelfRemovingSwitchPreference {
public LineageGlobalSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LineageGlobalSettingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LineageGlobalSettingSwitchPreference(Context context) {
super(context);
}
@Override
protected boolean isPersisted() {
return LineageSettings.Global.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putBoolean(String key, boolean value) {
LineageSettings.Global.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
protected boolean getBoolean(String key, boolean defaultValue) {
return LineageSettings.Global.getInt(getContext().getContentResolver(),
key, defaultValue ? 1 : 0) != 0;
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import lineageos.providers.LineageSettings;
public class LineageSecureSettingListPreference extends SelfRemovingListPreference {
public LineageSecureSettingListPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LineageSecureSettingListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public int getIntValue(int defValue) {
return getValue() == null ? defValue : Integer.valueOf(getValue());
}
@Override
protected boolean isPersisted() {
return LineageSettings.Secure.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putString(String key, String value) {
LineageSettings.Secure.putString(getContext().getContentResolver(), key, value);
}
@Override
protected String getString(String key, String defaultValue) {
return LineageSettings.Secure.getString(getContext().getContentResolver(),
key, defaultValue);
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright (C) 2021 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.PreferenceDataStore;
import com.android.settingslib.widget.MainSwitchPreference;
import lineageos.providers.LineageSettings;
public class LineageSecureSettingMainSwitchPreference extends MainSwitchPreference {
public LineageSecureSettingMainSwitchPreference(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setPreferenceDataStore(new DataStore());
}
public LineageSecureSettingMainSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPreferenceDataStore(new DataStore());
}
public LineageSecureSettingMainSwitchPreference(Context context) {
super(context);
setPreferenceDataStore(new DataStore());
}
private class DataStore extends PreferenceDataStore {
@Override
public void putBoolean(String key, boolean value) {
LineageSettings.Secure.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return LineageSettings.Secure.getInt(getContext().getContentResolver(), key,
defaultValue ? 1 : 0) != 0;
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import lineageos.providers.LineageSettings;
public class LineageSecureSettingSwitchPreference extends SelfRemovingSwitchPreference {
public LineageSecureSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LineageSecureSettingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LineageSecureSettingSwitchPreference(Context context) {
super(context);
}
@Override
protected boolean isPersisted() {
return LineageSettings.Secure.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putBoolean(String key, boolean value) {
LineageSettings.Secure.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
protected boolean getBoolean(String key, boolean defaultValue) {
return LineageSettings.Secure.getInt(getContext().getContentResolver(),
key, defaultValue ? 1 : 0) != 0;
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import lineageos.providers.LineageSettings;
public class LineageSystemSettingDropDownPreference extends SelfRemovingDropDownPreference {
public LineageSystemSettingDropDownPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LineageSystemSettingDropDownPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public int getIntValue(int defValue) {
return getValue() == null ? defValue : Integer.valueOf(getValue());
}
@Override
protected boolean isPersisted() {
return LineageSettings.System.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putString(String key, String value) {
LineageSettings.System.putString(getContext().getContentResolver(), key, value);
}
@Override
protected String getString(String key, String defaultValue) {
return LineageSettings.System.getString(getContext().getContentResolver(),
key, defaultValue);
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import lineageos.providers.LineageSettings;
public class LineageSystemSettingListPreference extends SelfRemovingListPreference {
public LineageSystemSettingListPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LineageSystemSettingListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public int getIntValue(int defValue) {
return getValue() == null ? defValue : Integer.valueOf(getValue());
}
@Override
protected boolean isPersisted() {
return LineageSettings.System.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putString(String key, String value) {
LineageSettings.System.putString(getContext().getContentResolver(), key, value);
}
@Override
protected String getString(String key, String defaultValue) {
return LineageSettings.System.getString(getContext().getContentResolver(),
key, defaultValue);
}
}

View File

@@ -1,58 +0,0 @@
/*
* Copyright (C) 2021 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.PreferenceDataStore;
import com.android.settingslib.widget.MainSwitchPreference;
import lineageos.providers.LineageSettings;
public class LineageSystemSettingMainSwitchPreference extends MainSwitchPreference {
public LineageSystemSettingMainSwitchPreference(Context context, AttributeSet attrs,
int defStyle) {
super(context, attrs, defStyle);
setPreferenceDataStore(new DataStore());
}
public LineageSystemSettingMainSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPreferenceDataStore(new DataStore());
}
public LineageSystemSettingMainSwitchPreference(Context context) {
super(context);
setPreferenceDataStore(new DataStore());
}
private class DataStore extends PreferenceDataStore {
@Override
public void putBoolean(String key, boolean value) {
LineageSettings.System.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return LineageSettings.System.getInt(getContext().getContentResolver(), key,
defaultValue ? 1 : 0) != 0;
}
}
}

View File

@@ -1,54 +0,0 @@
/*
* Copyright (C) 2015 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import lineageos.providers.LineageSettings;
public class LineageSystemSettingSwitchPreference extends SelfRemovingSwitchPreference {
public LineageSystemSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public LineageSystemSettingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public LineageSystemSettingSwitchPreference(Context context) {
super(context);
}
@Override
protected boolean isPersisted() {
return LineageSettings.System.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putBoolean(String key, boolean value) {
LineageSettings.System.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
protected boolean getBoolean(String key, boolean defaultValue) {
return LineageSettings.System.getInt(getContext().getContentResolver(),
key, defaultValue ? 1 : 0) != 0;
}
}

View File

@@ -1,180 +0,0 @@
/*
* 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 lineageos.preference;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.AttributeSet;
import android.util.Log;
import java.util.List;
import java.util.Objects;
/**
* A RemotePreference is a view into preference logic which lives in another
* process. The primary use case for this is at the platform level where
* many applications may be contributing their preferences into the
* Settings app.
*
* A RemotePreference appears as a PreferenceScreen and redirects to
* the real application when clicked. The remote application can
* send events back to the preference when data changes and the view
* needs to be updated. See RemotePreferenceUpdater for a base class
* to use on the application side which implements the listeners and
* protocol.
*
* The interprocess communication is realized using BroadcastReceivers.
* When the application wants to update the RemotePreference with
* new data, it sends an ACTION_REFRESH_PREFERENCE with a particular
* Uri. The RemotePreference listens while attached, and performs
* an ordered broadcast with ACTION_UPDATE_PREFERENCE back to
* the application, which is then returned to the preference after
* being filled with new data.
*
* The external activity should include the META_REMOTE_RECEIVER
* and (optionally) the META_REMOTE_KEY strings in it's metadata.
* META_REMOTE_RECEIVER must contain the class name of the
* RemotePreferenceUpdater which we should request updates from.
* META_REMOTE_KEY must contain the key used by the preference
* which should match on both sides.
*/
public class RemotePreference extends SelfRemovingPreference
implements RemotePreferenceManager.OnRemoteUpdateListener {
private static final String TAG = RemotePreference.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
public static final String ACTION_REFRESH_PREFERENCE =
"lineageos.intent.action.REFRESH_PREFERENCE";
public static final String ACTION_UPDATE_PREFERENCE =
"lineageos.intent.action.UPDATE_PREFERENCE";
public static final String META_REMOTE_RECEIVER =
"org.lineageos.settings.summary.receiver";
public static final String META_REMOTE_KEY =
"org.lineageos.settings.summary.key";
public static final String EXTRA_ENABLED = ":lineage:pref_enabled";
public static final String EXTRA_KEY = ":lineage:pref_key";
public static final String EXTRA_SUMMARY = ":lineage:pref_summary";
protected final Context mContext;
public RemotePreference(Context context, AttributeSet attrs,
int defStyle, int defStyleRes) {
super(context, attrs, defStyle, defStyleRes);
mContext = context;
}
public RemotePreference(Context context, AttributeSet attrs, int defStyle) {
this(context, attrs, defStyle, 0);
}
public RemotePreference(Context context, AttributeSet attrs) {
this(context, attrs, ConstraintsHelper.getAttr(context,
androidx.preference.R.attr.preferenceStyle,
android.R.attr.preferenceStyle));
}
@Override
public void onRemoteUpdated(Bundle bundle) {
if (DEBUG) Log.d(TAG, "onRemoteUpdated: " + bundle.toString());
if (bundle.containsKey(EXTRA_ENABLED)) {
boolean available = bundle.getBoolean(EXTRA_ENABLED, true);
if (available != isAvailable()) {
setAvailable(available);
}
}
if (isAvailable()) {
setSummary(bundle.getString(EXTRA_SUMMARY));
}
}
@Override
public void onAttached() {
super.onAttached();
if (isAvailable()) {
RemotePreferenceManager.get(mContext).attach(getKey(), this);
}
}
@Override
public void onDetached() {
super.onDetached();
RemotePreferenceManager.get(mContext).detach(getKey(), this);
}
protected String getRemoteKey(Bundle metaData) {
String remoteKey = metaData.getString(META_REMOTE_KEY);
return (remoteKey == null || !remoteKey.equals(getKey())) ? null : remoteKey;
}
@Override
public Intent getReceiverIntent() {
final Intent i = getIntent();
if (i == null) {
Log.w(TAG, "No target intent specified in preference!");
return null;
}
PackageManager pm = mContext.getPackageManager();
List<ResolveInfo> results = pm.queryIntentActivitiesAsUser(i,
PackageManager.MATCH_SYSTEM_ONLY | PackageManager.GET_META_DATA,
UserHandle.myUserId());
if (results.size() == 0) {
Log.w(TAG, "No activity found for: " + Objects.toString(i));
}
for (ResolveInfo resolved : results) {
ActivityInfo info = resolved.activityInfo;
Log.d(TAG, "ResolveInfo " + Objects.toString(resolved));
Bundle meta = info.metaData;
if (meta == null || !meta.containsKey(META_REMOTE_RECEIVER)) {
continue;
}
String receiverClass = meta.getString(META_REMOTE_RECEIVER);
String receiverPackage = info.packageName;
String remoteKey = getRemoteKey(meta);
if (DEBUG) Log.d(TAG, "getReceiverIntent class=" + receiverClass +
" package=" + receiverPackage + " key=" + remoteKey);
if (remoteKey == null) {
continue;
}
Intent ri = new Intent(ACTION_UPDATE_PREFERENCE);
ri.setComponent(new ComponentName(receiverPackage, receiverClass));
ri.putExtra(EXTRA_KEY, remoteKey);
return ri;
}
return null;
}
}

View File

@@ -1,181 +0,0 @@
/*
* 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 lineageos.preference;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;
import android.os.UserHandle;
import android.util.ArrayMap;
import android.util.Log;
import java.util.HashSet;
import java.util.Map;
import java.util.Objects;
import java.util.Set;
import lineageos.platform.Manifest;
import static lineageos.preference.RemotePreference.ACTION_REFRESH_PREFERENCE;
import static lineageos.preference.RemotePreference.ACTION_UPDATE_PREFERENCE;
import static lineageos.preference.RemotePreference.EXTRA_KEY;
/**
* Manages attaching and detaching of RemotePreferences and optimizes callbacks
* thru a single receiver on a separate thread.
*
* @hide
*/
public class RemotePreferenceManager {
private static final String TAG = RemotePreferenceManager.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(
RemotePreference.class.getSimpleName(), Log.VERBOSE);
private static RemotePreferenceManager sInstance;
private final Context mContext;
private final Map<String, Intent> mCache = new ArrayMap<>();
private final Map<String, Set<OnRemoteUpdateListener>> mCallbacks = new ArrayMap<>();
private final Handler mMainHandler = new Handler(Looper.getMainLooper());
private Handler mHandler;
private HandlerThread mThread;
public interface OnRemoteUpdateListener {
public Intent getReceiverIntent();
public void onRemoteUpdated(Bundle bundle);
}
private RemotePreferenceManager(Context context) {
mContext = context;
}
public synchronized static RemotePreferenceManager get(Context context) {
if (sInstance == null) {
sInstance = new RemotePreferenceManager(context.getApplicationContext());
}
return sInstance;
}
public void attach(String key, OnRemoteUpdateListener pref) {
Intent i;
synchronized (mCache) {
i = mCache.get(key);
if (i == null && !mCache.containsKey(key)) {
i = pref.getReceiverIntent();
mCache.put(key, i);
}
}
synchronized (mCallbacks) {
if (i != null) {
Set<OnRemoteUpdateListener> cbs = mCallbacks.get(key);
if (cbs == null) {
cbs = new HashSet<>();
mCallbacks.put(key, cbs);
if (mCallbacks.size() == 1) {
mThread = new HandlerThread("RemotePreference");
mThread.start();
mHandler = new Handler(mThread.getLooper());
mContext.registerReceiver(mListener,
new IntentFilter(ACTION_REFRESH_PREFERENCE),
Manifest.permission.MANAGE_REMOTE_PREFERENCES, mHandler);
}
}
cbs.add(pref);
requestUpdate(key);
}
}
}
public void detach(String key, OnRemoteUpdateListener pref) {
synchronized (mCallbacks) {
Set<OnRemoteUpdateListener> cbs = mCallbacks.get(key);
if (cbs != null && cbs.remove(pref) && cbs.isEmpty()
&& mCallbacks.remove(key) != null && mCallbacks.isEmpty()) {
mContext.unregisterReceiver(mListener);
if (mThread != null) {
mThread.quit();
mThread = null;
}
mHandler = null;
}
}
}
private void requestUpdate(String key) {
synchronized (mCache) {
Intent i = mCache.get(key);
if (i == null) {
return;
}
mContext.sendOrderedBroadcastAsUser(i, UserHandle.CURRENT,
Manifest.permission.MANAGE_REMOTE_PREFERENCES,
mListener, mHandler, Activity.RESULT_OK, null, null);
}
}
private final BroadcastReceiver mListener = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) Log.d(TAG, "onReceive: intent=" + Objects.toString(intent));
if (ACTION_REFRESH_PREFERENCE.equals(intent.getAction())) {
final String key = intent.getStringExtra(EXTRA_KEY);
synchronized (mCallbacks) {
if (key != null && mCallbacks.containsKey(key)) {
requestUpdate(key);
}
}
} else if (ACTION_UPDATE_PREFERENCE.equals(intent.getAction())) {
if (getAbortBroadcast()) {
Log.e(TAG, "Broadcast aborted, code=" + getResultCode());
return;
}
final Bundle bundle = getResultExtras(true);
final String key = bundle.getString(EXTRA_KEY);
synchronized (mCallbacks) {
if (key != null && mCallbacks.containsKey(key)) {
mMainHandler.post(new Runnable() {
@Override
public void run() {
synchronized (mCallbacks) {
if (mCallbacks.containsKey(key)) {
Set<OnRemoteUpdateListener> cbs = mCallbacks.get(key);
if (cbs != null) {
for (OnRemoteUpdateListener cb : cbs) {
cb.onRemoteUpdated(bundle);
}
}
}
}
}
});
}
}
}
}
};
}

View File

@@ -1,129 +0,0 @@
/*
* 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 lineageos.preference;
import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.UserHandle;
import android.util.Log;
import java.util.Objects;
import lineageos.platform.Manifest;
/**
* Base class for remote summary providers.
* <p>
* When an application is hosting preferences which are served by a different process,
* the former needs to stay updated with changes in order to display the correct
* summary when the user returns to the latter.
* <p>
* This class implements a simple ordered broadcast mechanism where the application
* running the RemotePreference sends an explicit broadcast to the host, who
* fills out the extras in the result bundle and returns it to the caller.
* <p>
* A minimal implementation will override getSummary and return a summary
* for the given key. Alternatively, fillResultExtras can be overridden
* if additional data should be added to the result.
*/
public class RemotePreferenceUpdater extends BroadcastReceiver {
private static final String TAG = RemotePreferenceUpdater.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(
RemotePreference.class.getSimpleName(), Log.VERBOSE);
private static Intent getTargetIntent(Context context, String key) {
final Intent i = new Intent(RemotePreference.ACTION_REFRESH_PREFERENCE);
i.putExtra(RemotePreference.EXTRA_KEY, key);
return i;
}
/**
* Fetch the updated summary for the given key
*
* @param key
* @return the summary for the given key
*/
protected String getSummary(Context context, String key) {
return null;
}
/**
* Fill the bundle with the summary and any other data needed to update
* the client.
*
* @param context
* @param key
* @param extras
* @return true if successful
*/
protected boolean fillResultExtras(Context context, String key, Bundle extras) {
extras.putString(RemotePreference.EXTRA_KEY, key);
final String summary = getSummary(context, key);
if (summary == null) {
return false;
}
extras.putString(RemotePreference.EXTRA_SUMMARY, summary);
return true;
}
/**
* @hide
*/
@Override
public void onReceive(Context context, Intent intent) {
if (isOrderedBroadcast() &&
RemotePreference.ACTION_UPDATE_PREFERENCE.equals(intent.getAction())) {
final String key = intent.getStringExtra(RemotePreference.EXTRA_KEY);
if (DEBUG) Log.d(TAG, "onReceive key=" +key +
" intent=" + Objects.toString(intent) +
" extras=" + Objects.toString(intent.getExtras()));
if (key != null) {
if (fillResultExtras(context, key, getResultExtras(true))) {
setResultCode(Activity.RESULT_OK);
if (DEBUG) Log.d(TAG, "onReceive result=" +
Objects.toString(getResultExtras(true)));
return;
}
}
abortBroadcast();
}
}
/**
* Tell the RemotePreference that updated state is available. Call from
* the fragment when necessary.
*
* @param context
* @param key
*/
public static void notifyChanged(Context context, String key) {
if (DEBUG) Log.d(TAG, "notifyChanged: key=" + key +
" target=" + Objects.toString(getTargetIntent(context, key)));
context.sendBroadcastAsUser(getTargetIntent(context, key),
UserHandle.CURRENT, Manifest.permission.MANAGE_REMOTE_PREFERENCES);
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2021 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
import androidx.preference.PreferenceDataStore;
import com.android.settingslib.widget.MainSwitchPreference;
public class SecureSettingMainSwitchPreference extends MainSwitchPreference {
public SecureSettingMainSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setPreferenceDataStore(new DataStore());
}
public SecureSettingMainSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPreferenceDataStore(new DataStore());
}
public SecureSettingMainSwitchPreference(Context context) {
super(context, null);
setPreferenceDataStore(new DataStore());
}
private class DataStore extends PreferenceDataStore {
@Override
public void putBoolean(String key, boolean value) {
Settings.Secure.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return Settings.Secure.getInt(getContext().getContentResolver(), key,
defaultValue ? 1 : 0) != 0;
}
}
}

View File

@@ -1,53 +0,0 @@
/**
* Copyright (C) 2014-2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
public class SecureSettingSwitchPreference extends SelfRemovingSwitchPreference {
public SecureSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SecureSettingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SecureSettingSwitchPreference(Context context) {
super(context, null);
}
@Override
protected boolean isPersisted() {
return Settings.Secure.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putBoolean(String key, boolean value) {
Settings.Secure.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
protected boolean getBoolean(String key, boolean defaultValue) {
return Settings.Secure.getInt(getContext().getContentResolver(),
key, defaultValue ? 1 : 0) != 0;
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.DropDownPreference;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceViewHolder;
/**
* A Preference which can automatically remove itself from the hierarchy
* based on constraints set in XML.
*/
public abstract class SelfRemovingDropDownPreference extends DropDownPreference {
private final ConstraintsHelper mConstraints;
public SelfRemovingDropDownPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mConstraints = new ConstraintsHelper(context, attrs, this);
setPreferenceDataStore(new DataStore());
}
public SelfRemovingDropDownPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mConstraints = new ConstraintsHelper(context, attrs, this);
setPreferenceDataStore(new DataStore());
}
public SelfRemovingDropDownPreference(Context context) {
super(context);
mConstraints = new ConstraintsHelper(context, null, this);
setPreferenceDataStore(new DataStore());
}
@Override
public void onAttached() {
super.onAttached();
mConstraints.onAttached();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mConstraints.onBindViewHolder(holder);
}
public void setAvailable(boolean available) {
mConstraints.setAvailable(available);
}
public boolean isAvailable() {
return mConstraints.isAvailable();
}
protected abstract boolean isPersisted();
protected abstract void putString(String key, String value);
protected abstract String getString(String key, String defaultValue);
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
final String value;
if (!restorePersistedValue || !isPersisted()) {
if (defaultValue == null) {
return;
}
value = (String) defaultValue;
if (shouldPersist()) {
persistString(value);
}
} else {
// Note: the default is not used because to have got here
// isPersisted() must be true.
value = getString(getKey(), null /* not used */);
}
setValue(value);
}
private class DataStore extends PreferenceDataStore {
@Override
public void putString(String key, String value) {
SelfRemovingDropDownPreference.this.putString(key, value);
}
@Override
public String getString(String key, String defaultValue) {
return SelfRemovingDropDownPreference.this.getString(key, defaultValue);
}
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.ListPreference;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceViewHolder;
/**
* A Preference which can automatically remove itself from the hierarchy
* based on constraints set in XML.
*/
public abstract 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);
setPreferenceDataStore(new DataStore());
}
public SelfRemovingListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mConstraints = new ConstraintsHelper(context, attrs, this);
setPreferenceDataStore(new DataStore());
}
public SelfRemovingListPreference(Context context) {
super(context);
mConstraints = new ConstraintsHelper(context, null, this);
setPreferenceDataStore(new DataStore());
}
@Override
public void onAttached() {
super.onAttached();
mConstraints.onAttached();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mConstraints.onBindViewHolder(holder);
}
public void setAvailable(boolean available) {
mConstraints.setAvailable(available);
}
public boolean isAvailable() {
return mConstraints.isAvailable();
}
protected abstract boolean isPersisted();
protected abstract void putString(String key, String value);
protected abstract String getString(String key, String defaultValue);
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
final String value;
if (!restorePersistedValue || !isPersisted()) {
if (defaultValue == null) {
return;
}
value = (String) defaultValue;
if (shouldPersist()) {
persistString(value);
}
} else {
// Note: the default is not used because to have got here
// isPersisted() must be true.
value = getString(getKey(), null /* not used */);
}
setValue(value);
}
private class DataStore extends PreferenceDataStore {
@Override
public void putString(String key, String value) {
SelfRemovingListPreference.this.putString(key, value);
}
@Override
public String getString(String key, String defaultValue) {
return SelfRemovingListPreference.this.getString(key, defaultValue);
}
}
}

View File

@@ -1,71 +0,0 @@
/*
* 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.Preference;
import androidx.preference.PreferenceViewHolder;
/**
* 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, int defStyleRes) {
super(context, attrs, defStyle, defStyleRes);
mConstraints = new ConstraintsHelper(context, attrs, this);
}
public SelfRemovingPreference(Context context, AttributeSet attrs, int defStyle) {
this(context, attrs, defStyle, 0);
}
public SelfRemovingPreference(Context context, AttributeSet attrs) {
this(context, attrs, ConstraintsHelper.getAttr(context,
androidx.preference.R.attr.preferenceStyle,
android.R.attr.preferenceStyle));
}
public SelfRemovingPreference(Context context) {
this(context, null);
}
@Override
public void onAttached() {
super.onAttached();
mConstraints.onAttached();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mConstraints.onBindViewHolder(holder);
}
public void setAvailable(boolean available) {
mConstraints.setAvailable(available);
}
public boolean isAvailable() {
return mConstraints.isAvailable();
}
}

View File

@@ -1,106 +0,0 @@
/*
* Copyright (C) 2016 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.util.AttributeSet;
import androidx.preference.PreferenceDataStore;
import androidx.preference.PreferenceViewHolder;
import androidx.preference.SwitchPreference;
/**
* A SwitchPreference which can automatically remove itself from the hierarchy
* based on constraints set in XML.
*/
public abstract 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);
setPreferenceDataStore(new DataStore());
}
public SelfRemovingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
mConstraints = new ConstraintsHelper(context, attrs, this);
setPreferenceDataStore(new DataStore());
}
public SelfRemovingSwitchPreference(Context context) {
super(context);
mConstraints = new ConstraintsHelper(context, null, this);
setPreferenceDataStore(new DataStore());
}
@Override
public void onAttached() {
super.onAttached();
mConstraints.onAttached();
}
@Override
public void onBindViewHolder(PreferenceViewHolder holder) {
super.onBindViewHolder(holder);
mConstraints.onBindViewHolder(holder);
}
public void setAvailable(boolean available) {
mConstraints.setAvailable(available);
}
public boolean isAvailable() {
return mConstraints.isAvailable();
}
protected abstract boolean isPersisted();
protected abstract void putBoolean(String key, boolean value);
protected abstract boolean getBoolean(String key, boolean defaultValue);
@Override
protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {
final boolean checked;
if (!restorePersistedValue || !isPersisted()) {
if (defaultValue == null) {
return;
}
checked = (boolean) defaultValue;
if (shouldPersist()) {
persistBoolean(checked);
}
} else {
// Note: the default is not used because to have got here
// isPersisted() must be true.
checked = getBoolean(getKey(), false /* not used */);
}
setChecked(checked);
}
private class DataStore extends PreferenceDataStore {
@Override
public void putBoolean(String key, boolean value) {
SelfRemovingSwitchPreference.this.putBoolean(key, value);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return SelfRemovingSwitchPreference.this.getBoolean(key, defaultValue);
}
}
}

View File

@@ -1,227 +0,0 @@
/*
* 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 lineageos.preference;
import android.content.ContentResolver;
import android.content.Context;
import android.database.ContentObserver;
import android.net.Uri;
import android.os.Handler;
import android.provider.Settings;
import android.util.ArrayMap;
import android.util.ArraySet;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import lineageos.providers.LineageSettings;
public class SettingsHelper {
private static final String SETTINGS_GLOBAL = Settings.Global.CONTENT_URI.toString();
private static final String SETTINGS_SECURE = Settings.Secure.CONTENT_URI.toString();
private static final String SETTINGS_SYSTEM = Settings.System.CONTENT_URI.toString();
private static final String LINEAGESETTINGS_GLOBAL = LineageSettings.Global.CONTENT_URI.toString();
private static final String LINEAGESETTINGS_SECURE = LineageSettings.Secure.CONTENT_URI.toString();
private static final String LINEAGESETTINGS_SYSTEM = LineageSettings.System.CONTENT_URI.toString();
private static SettingsHelper sInstance;
private final Context mContext;
private final Observatory mObservatory;
private SettingsHelper(Context context) {
mContext = context;
mObservatory = new Observatory(context, new Handler());
}
public static synchronized SettingsHelper get(Context context) {
if (sInstance == null) {
sInstance = new SettingsHelper(context);
}
return sInstance;
}
public String getString(Uri settingsUri) {
final String uri = settingsUri.toString();
final ContentResolver resolver = mContext.getContentResolver();
if (uri.startsWith(SETTINGS_SECURE)) {
return Settings.Secure.getString(resolver, uri.substring(SETTINGS_SECURE.length()));
} else if (uri.startsWith(SETTINGS_SYSTEM)) {
return Settings.System.getString(resolver, uri.substring(SETTINGS_SYSTEM.length()));
} else if (uri.startsWith(SETTINGS_GLOBAL)) {
return Settings.Global.getString(resolver, uri.substring(SETTINGS_GLOBAL.length()));
} else if (uri.startsWith(LINEAGESETTINGS_SECURE)) {
return LineageSettings.Secure.getString(resolver, uri.substring(LINEAGESETTINGS_SECURE.length()));
} else if (uri.startsWith(LINEAGESETTINGS_SYSTEM)) {
return LineageSettings.System.getString(resolver, uri.substring(LINEAGESETTINGS_SYSTEM.length()));
} else if (uri.startsWith(LINEAGESETTINGS_GLOBAL)) {
return LineageSettings.Global.getString(resolver, uri.substring(LINEAGESETTINGS_GLOBAL.length()));
}
return null;
}
public int getInt(Uri settingsUri, int def) {
final String uri = settingsUri.toString();
final ContentResolver resolver = mContext.getContentResolver();
if (uri.startsWith(SETTINGS_SECURE)) {
return Settings.Secure.getInt(resolver, uri.substring(SETTINGS_SECURE.length()), def);
} else if (uri.startsWith(SETTINGS_SYSTEM)) {
return Settings.System.getInt(resolver, uri.substring(SETTINGS_SYSTEM.length()), def);
} else if (uri.startsWith(SETTINGS_GLOBAL)) {
return Settings.Global.getInt(resolver, uri.substring(SETTINGS_GLOBAL.length()), def);
} else if (uri.startsWith(LINEAGESETTINGS_SECURE)) {
return LineageSettings.Secure.getInt(resolver, uri.substring(LINEAGESETTINGS_SECURE.length()), def);
} else if (uri.startsWith(LINEAGESETTINGS_SYSTEM)) {
return LineageSettings.System.getInt(resolver, uri.substring(LINEAGESETTINGS_SYSTEM.length()), def);
} else if (uri.startsWith(LINEAGESETTINGS_GLOBAL)) {
return LineageSettings.Global.getInt(resolver, uri.substring(LINEAGESETTINGS_GLOBAL.length()), def);
}
return def;
}
public boolean getBoolean(Uri settingsUri, boolean def) {
int value = getInt(settingsUri, def ? 1 : 0);
return value == 1;
}
public void putString(Uri settingsUri, String value) {
final String uri = settingsUri.toString();
final ContentResolver resolver = mContext.getContentResolver();
if (uri.startsWith(SETTINGS_SECURE)) {
Settings.Secure.putString(resolver, uri.substring(SETTINGS_SECURE.length()), value);
} else if (uri.startsWith(SETTINGS_SYSTEM)) {
Settings.System.putString(resolver, uri.substring(SETTINGS_SYSTEM.length()), value);
} else if (uri.startsWith(SETTINGS_GLOBAL)) {
Settings.Global.putString(resolver, uri.substring(SETTINGS_GLOBAL.length()), value);
} else if (uri.startsWith(LINEAGESETTINGS_SECURE)) {
LineageSettings.Secure.putString(resolver, uri.substring(LINEAGESETTINGS_SECURE.length()), value);
} else if (uri.startsWith(LINEAGESETTINGS_SYSTEM)) {
LineageSettings.System.putString(resolver, uri.substring(LINEAGESETTINGS_SYSTEM.length()), value);
} else if (uri.startsWith(LINEAGESETTINGS_GLOBAL)) {
LineageSettings.Global.putString(resolver, uri.substring(LINEAGESETTINGS_GLOBAL.length()), value);
}
}
public void putInt(Uri settingsUri, int value) {
final String uri = settingsUri.toString();
final ContentResolver resolver = mContext.getContentResolver();
if (uri.startsWith(SETTINGS_SECURE)) {
Settings.Secure.putInt(resolver, uri.substring(SETTINGS_SECURE.length()), value);
} else if (uri.startsWith(SETTINGS_SYSTEM)) {
Settings.System.putInt(resolver, uri.substring(SETTINGS_SYSTEM.length()), value);
} else if (uri.startsWith(SETTINGS_GLOBAL)) {
Settings.Global.putInt(resolver, uri.substring(SETTINGS_GLOBAL.length()), value);
} else if (uri.startsWith(LINEAGESETTINGS_SECURE)) {
LineageSettings.Secure.putInt(resolver, uri.substring(LINEAGESETTINGS_SECURE.length()), value);
} else if (uri.startsWith(LINEAGESETTINGS_SYSTEM)) {
LineageSettings.System.putInt(resolver, uri.substring(LINEAGESETTINGS_SYSTEM.length()), value);
} else if (uri.startsWith(LINEAGESETTINGS_GLOBAL)) {
LineageSettings.Global.putInt(resolver, uri.substring(LINEAGESETTINGS_GLOBAL.length()), value);
}
}
public void putBoolean(Uri settingsUri, boolean value) {
putInt(settingsUri, value ? 1 : 0);
}
public void startWatching(OnSettingsChangeListener listener, Uri... settingsUris) {
mObservatory.register(listener, settingsUris);
}
public void stopWatching(OnSettingsChangeListener listener) {
mObservatory.unregister(listener);
}
public interface OnSettingsChangeListener {
public void onSettingsChanged(Uri settingsUri);
}
/**
* A scalable ContentObserver that aggregates all listeners thru a single entrypoint.
*/
private static class Observatory extends ContentObserver {
private final Map<OnSettingsChangeListener, Set<Uri>> mTriggers = new ArrayMap<>();
private final List<Uri> mRefs = new ArrayList<>();
private final Context mContext;
private final ContentResolver mResolver;
public Observatory(Context context, Handler handler) {
super(handler);
mContext = context;
mResolver = mContext.getContentResolver();
}
public void register(OnSettingsChangeListener listener, Uri... contentUris) {
synchronized (mRefs) {
Set<Uri> uris = mTriggers.get(listener);
if (uris == null) {
uris = new ArraySet<Uri>();
mTriggers.put(listener, uris);
}
for (Uri contentUri : contentUris) {
uris.add(contentUri);
if (!mRefs.contains(contentUri)) {
mResolver.registerContentObserver(contentUri, false, this);
listener.onSettingsChanged(null);
}
mRefs.add(contentUri);
}
}
}
public void unregister(OnSettingsChangeListener listener) {
synchronized (mRefs) {
Set<Uri> uris = mTriggers.remove(listener);
if (uris != null) {
for (Uri uri : uris) {
mRefs.remove(uri);
}
}
if (mRefs.size() == 0) {
mResolver.unregisterContentObserver(this);
}
}
}
@Override
public void onChange(boolean selfChange, Uri uri) {
synchronized (mRefs) {
super.onChange(selfChange, uri);
final Set<OnSettingsChangeListener> notify = new ArraySet<>();
for (Map.Entry<OnSettingsChangeListener, Set<Uri>> entry : mTriggers.entrySet()) {
if (entry.getValue().contains(uri)) {
notify.add(entry.getKey());
}
}
for (OnSettingsChangeListener listener : notify) {
listener.onSettingsChanged(uri);
}
}
}
}
}

View File

@@ -1,56 +0,0 @@
/*
* Copyright (C) 2021 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
import androidx.preference.PreferenceDataStore;
import com.android.settingslib.widget.MainSwitchPreference;
public class SystemSettingMainSwitchPreference extends MainSwitchPreference {
public SystemSettingMainSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
setPreferenceDataStore(new DataStore());
}
public SystemSettingMainSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
setPreferenceDataStore(new DataStore());
}
public SystemSettingMainSwitchPreference(Context context) {
super(context, null);
setPreferenceDataStore(new DataStore());
}
private class DataStore extends PreferenceDataStore {
@Override
public void putBoolean(String key, boolean value) {
Settings.System.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
public boolean getBoolean(String key, boolean defaultValue) {
return Settings.System.getInt(getContext().getContentResolver(), key,
defaultValue ? 1 : 0) != 0;
}
}
}

View File

@@ -1,53 +0,0 @@
/*
* Copyright (C) 2013 The CyanogenMod Project
* Copyright (C) 2018 The LineageOS 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 lineageos.preference;
import android.content.Context;
import android.provider.Settings;
import android.util.AttributeSet;
public class SystemSettingSwitchPreference extends SelfRemovingSwitchPreference {
public SystemSettingSwitchPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public SystemSettingSwitchPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public SystemSettingSwitchPreference(Context context) {
super(context, null);
}
@Override
protected boolean isPersisted() {
return Settings.System.getString(getContext().getContentResolver(), getKey()) != null;
}
@Override
protected void putBoolean(String key, boolean value) {
Settings.System.putInt(getContext().getContentResolver(), key, value ? 1 : 0);
}
@Override
protected boolean getBoolean(String key, boolean defaultValue) {
return Settings.System.getInt(getContext().getContentResolver(),
key, defaultValue ? 1 : 0) != 0;
}
}

View File

@@ -1,83 +0,0 @@
/*
* 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 org.lineageos.internal.lineageparts;
import android.content.Context;
import android.os.Bundle;
import android.util.AttributeSet;
import lineageos.preference.RemotePreference;
/**
* A link to a remote preference screen which can be used with a minimum amount
* of information. Supports summary updates asynchronously.
*/
public class LineagePartsPreference extends RemotePreference {
private static final String TAG = "LineagePartsPreference";
private final PartInfo mPart;
private final Context mContext;
public LineagePartsPreference(Context context, AttributeSet attrs,
int defStyle, int defStyleRes) {
super(context, attrs, defStyle, defStyleRes);
mContext = context;
mPart = PartsList.get(context).getPartInfo(getKey());
if (mPart == null) {
throw new RuntimeException("Part not found: " + getKey());
}
updatePreference();
setIntent(mPart.getIntentForActivity());
}
public LineagePartsPreference(Context context, AttributeSet attrs, int defStyle) {
this(context, attrs, defStyle, 0);
}
public LineagePartsPreference(Context context, AttributeSet attrs) {
this(context, attrs, androidx.preference.R.attr.preferenceStyle);
}
@Override
public void onRemoteUpdated(Bundle bundle) {
if (bundle.containsKey(PartsList.EXTRA_PART)) {
PartInfo update = bundle.getParcelable(PartsList.EXTRA_PART);
if (update != null) {
mPart.updateFrom(update);
updatePreference();
}
}
}
@Override
protected String getRemoteKey(Bundle metaData) {
// remote key is the same as ours
return getKey();
}
private void updatePreference() {
if (isAvailable() != mPart.isAvailable()) {
setAvailable(mPart.isAvailable());
}
if (isAvailable()) {
setTitle(mPart.getTitle());
setSummary(mPart.getSummary());
}
}
}

View File

@@ -1,19 +0,0 @@
/*
* 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 org.lineageos.internal.lineageparts;
parcelable PartInfo;

View File

@@ -1,199 +0,0 @@
/*
* 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 org.lineageos.internal.lineageparts;
import android.content.Intent;
import android.os.Parcel;
import android.os.Parcelable;
import java.util.Objects;
import lineageos.os.Concierge;
public class PartInfo implements Parcelable {
private static final String TAG = PartInfo.class.getSimpleName();
private final String mName;
private String mTitle;
private String mSummary;
private String mFragmentClass;
private int mIconRes;
private boolean mAvailable = true;
/* for search provider */
private int mXmlRes = 0;
public PartInfo(String name, String title, String summary) {
mName = name;
mTitle = title;
mSummary = summary;
}
public PartInfo(String name) {
this(name, null, null);
}
public PartInfo(Parcel parcel) {
Concierge.ParcelInfo parcelInfo = Concierge.receiveParcel(parcel);
int parcelableVersion = parcelInfo.getParcelVersion();
mName = parcel.readString();
mTitle = parcel.readString();
mSummary = parcel.readString();
mFragmentClass = parcel.readString();
mIconRes = parcel.readInt();
mAvailable = parcel.readInt() == 1;
mXmlRes = parcel.readInt();
}
public String getName() {
return mName;
}
public void setTitle(String title) {
mTitle = title;
}
public String getTitle() {
return mTitle;
}
public void setSummary(String summary) {
mSummary = summary;
}
public String getSummary() {
return mSummary;
}
public String getFragmentClass() {
return mFragmentClass;
}
public void setFragmentClass(String fragmentClass) {
mFragmentClass = fragmentClass;
}
public int getIconRes() {
return mIconRes;
}
public void setIconRes(int iconRes) {
mIconRes = iconRes;
}
public boolean isAvailable() {
return mAvailable;
}
public void setAvailable(boolean available) {
mAvailable = available;
}
public int getXmlRes() {
return mXmlRes;
}
public void setXmlRes(int xmlRes) {
mXmlRes = xmlRes;
}
public boolean updateFrom(PartInfo other) {
if (other == null) {
return false;
}
if (other.equals(this)) {
return false;
}
setTitle(other.getTitle());
setSummary(other.getSummary());
setFragmentClass(other.getFragmentClass());
setIconRes(other.getIconRes());
setAvailable(other.isAvailable());
setXmlRes(other.getXmlRes());
return true;
}
@Override
public String toString() {
return String.format("PartInfo=[ name=%s title=%s summary=%s fragment=%s xmlRes=%x ]",
mName, mTitle, mSummary, mFragmentClass, mXmlRes);
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel out, int i) {
Concierge.ParcelInfo parcelInfo = Concierge.prepareParcel(out);
out.writeString(mName);
out.writeString(mTitle);
out.writeString(mSummary);
out.writeString(mFragmentClass);
out.writeInt(mIconRes);
out.writeInt(mAvailable ? 1 : 0);
out.writeInt(mXmlRes);
parcelInfo.complete();
}
@Override
public boolean equals(Object other) {
if (other == null) {
return false;
}
if (getClass() != other.getClass()) {
return false;
}
PartInfo o = (PartInfo) other;
return Objects.equals(mName, o.mName) && Objects.equals(mTitle, o.mTitle) &&
Objects.equals(mSummary, o.mSummary) && Objects.equals(mFragmentClass, o.mFragmentClass) &&
Objects.equals(mIconRes, o.mIconRes) && Objects.equals(mAvailable, o.mAvailable) &&
Objects.equals(mXmlRes, o.mXmlRes);
}
public String getAction() {
return PartsList.PARTS_ACTION_PREFIX + "." + mName;
}
public Intent getIntentForActivity() {
Intent i = new Intent(getAction());
i.setComponent(PartsList.LINEAGEPARTS_ACTIVITY);
return i;
}
public static final Parcelable.Creator<PartInfo> CREATOR = new Parcelable.Creator<PartInfo>() {
@Override
public PartInfo createFromParcel(Parcel in) {
return new PartInfo(in);
}
@Override
public PartInfo[] newArray(int size) {
return new PartInfo[size];
}
};
}

View File

@@ -1,212 +0,0 @@
/*
* 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 org.lineageos.internal.lineageparts;
import android.content.ComponentName;
import android.content.Context;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.content.res.XmlResourceParser;
import android.util.ArrayMap;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import android.util.Xml;
import com.android.internal.util.XmlUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.util.Map;
import java.util.Set;
import static com.android.internal.R.styleable.Preference;
import static com.android.internal.R.styleable.Preference_fragment;
import static com.android.internal.R.styleable.Preference_icon;
import static com.android.internal.R.styleable.Preference_key;
import static com.android.internal.R.styleable.Preference_summary;
import static com.android.internal.R.styleable.Preference_title;
import static lineageos.platform.R.styleable.lineage_Searchable;
import static lineageos.platform.R.styleable.lineage_Searchable_xmlRes;
public class PartsList {
private static final String TAG = PartsList.class.getSimpleName();
private static final boolean DEBUG = Log.isLoggable(TAG, Log.VERBOSE);
public static final String EXTRA_PART = ":lineage:part";
public static final String LINEAGEPARTS_PACKAGE = "org.lineageos.lineageparts";
public static final ComponentName LINEAGEPARTS_ACTIVITY = new ComponentName(
LINEAGEPARTS_PACKAGE, LINEAGEPARTS_PACKAGE + ".PartsActivity");
public static final String PARTS_ACTION_PREFIX = LINEAGEPARTS_PACKAGE + ".parts";
private final Map<String, PartInfo> mParts = new ArrayMap<>();
private final Context mContext;
private static PartsList sInstance;
private static final Object sInstanceLock = new Object();
private PartsList(Context context) {
mContext = context;
loadParts();
}
public static PartsList get(Context context) {
synchronized (sInstanceLock) {
if (sInstance == null) {
sInstance = new PartsList(context);
}
return sInstance;
}
}
private void loadParts() {
synchronized (mParts) {
final PackageManager pm = mContext.getPackageManager();
try {
final Resources r = pm.getResourcesForApplication(LINEAGEPARTS_PACKAGE);
if (r == null) {
return;
}
int resId = r.getIdentifier("parts_catalog", "xml", LINEAGEPARTS_PACKAGE);
if (resId > 0) {
loadPartsFromResourceLocked(r, resId, mParts);
}
} catch (PackageManager.NameNotFoundException e) {
// no lineageparts installed
}
}
}
public Set<String> getPartsList() {
synchronized (mParts) {
return mParts.keySet();
}
}
public PartInfo getPartInfo(String key) {
synchronized (mParts) {
return mParts.get(key);
}
}
public final PartInfo getPartInfoForClass(String clazz) {
synchronized (mParts) {
for (PartInfo info : mParts.values()) {
if (info.getFragmentClass() != null && info.getFragmentClass().equals(clazz)) {
return info;
}
}
return null;
}
}
private void loadPartsFromResourceLocked(Resources res, int resid,
Map<String, PartInfo> target) {
XmlResourceParser parser = null;
try {
parser = res.getXml(resid);
AttributeSet attrs = Xml.asAttributeSet(parser);
int type;
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& type != XmlPullParser.START_TAG) {
// Parse next until start tag is found
}
String nodeName = parser.getName();
if (!"parts-catalog".equals(nodeName)) {
throw new RuntimeException(
"XML document must start with <parts-catalog> tag; found "
+ nodeName + " at " + parser.getPositionDescription());
}
final int outerDepth = parser.getDepth();
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
&& (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
continue;
}
nodeName = parser.getName();
if ("part".equals(nodeName)) {
TypedArray sa = res.obtainAttributes(attrs, Preference);
String key = null;
TypedValue tv = sa.peekValue(Preference_key);
if (tv != null && tv.type == TypedValue.TYPE_STRING) {
if (tv.resourceId != 0) {
key = res.getString(tv.resourceId);
} else {
key = String.valueOf(tv.string);
}
}
if (key == null) {
throw new RuntimeException("Attribute 'key' is required");
}
final PartInfo info = new PartInfo(key);
tv = sa.peekValue(Preference_title);
if (tv != null && tv.type == TypedValue.TYPE_STRING) {
if (tv.resourceId != 0) {
info.setTitle(res.getString(tv.resourceId));
} else {
info.setTitle(String.valueOf(tv.string));
}
}
tv = sa.peekValue(Preference_summary);
if (tv != null && tv.type == TypedValue.TYPE_STRING) {
if (tv.resourceId != 0) {
info.setSummary(res.getString(tv.resourceId));
} else {
info.setSummary(String.valueOf(tv.string));
}
}
info.setFragmentClass(sa.getString(Preference_fragment));
info.setIconRes(sa.getResourceId(Preference_icon, 0));
sa = res.obtainAttributes(attrs, lineage_Searchable);
info.setXmlRes(sa.getResourceId(lineage_Searchable_xmlRes, 0));
sa.recycle();
target.put(key, info);
} else {
XmlUtils.skipCurrentTag(parser);
}
}
} catch (XmlPullParserException e) {
throw new RuntimeException("Error parsing catalog", e);
} catch (IOException e) {
throw new RuntimeException("Error parsing catalog", e);
} finally {
if (parser != null) parser.close();
}
}
}