package biz.bokhorst.xprivacy;
import android.annotation.SuppressLint;
import android.os.Build;
public class Hook implements Comparable<Hook> {
private String mRestrictionName;
private String mMethodName;
private String[] mPermissions;
private int mSdkFrom;
private int mSdkTo = Integer.MAX_VALUE;
private Version mFrom;
private String mReplacedRestriction;
private String mReplacedMethod;
private boolean mDangerous = false;
private boolean mRestart = false;
private boolean mNoUsageData = false;
private boolean mNoOnDemand = false;
private String mWhitelist = null;
private boolean mNotify = false;
private int mAOSPSdk = 0;
private int mNotAOSPSdk = 0;
private boolean mUnsafe = false;
private boolean mOptional = false;
private boolean mObsolete = false;
private String mAnnotation = null;
public Hook(String restrictionName, String methodName) {
mRestrictionName = restrictionName;
mMethodName = methodName;
}
public Hook(String restrictionName, String methodName, String permissions, int sdk, String from, String replaces) {
mRestrictionName = restrictionName;
mMethodName = methodName;
mPermissions = (permissions == null ? null : permissions.split(","));
mSdkFrom = sdk;
mFrom = (from == null ? null : new Version(from));
if (replaces != null) {
int slash = replaces.indexOf('/');
if (slash > 0) {
mReplacedRestriction = replaces.substring(0, slash);
mReplacedMethod = replaces.substring(slash + 1);
if ("".equals(mReplacedMethod))
mReplacedMethod = methodName;
} else {
mReplacedRestriction = mRestrictionName;
mReplacedMethod = replaces;
}
}
}
// Definitions
public Hook to(int sdk) {
mSdkTo = sdk;
return this;
}
public Hook dangerous() {
mDangerous = true;
return this;
}
@SuppressLint("FieldGetter")
public void toggleDangerous() {
String name = String.format("%s.%s.%s", PrivacyManager.cSettingDangerous, this.getRestrictionName(),
this.getName());
PrivacyManager.setSetting(0, name, Boolean.toString(!isDangerous()));
}
public Hook restart() {
mRestart = true;
return this;
}
public Hook noUsageData() {
mNoUsageData = true;
return this;
}
public Hook noOnDemand() {
mNoOnDemand = true;
return this;
}
public Hook whitelist(String whitelist) {
mWhitelist = whitelist;
return this;
}
public Hook doNotify() {
mNotify = true;
return this;
}
public Hook AOSP(int sdk) {
mAOSPSdk = sdk;
return this;
}
public Hook notAOSP(int sdk) {
mNotAOSPSdk = sdk;
if (!PrivacyManager.cIPC.equals(mRestrictionName))
mUnsafe = true;
return this;
}
public Hook unsafe() {
mUnsafe = true;
return this;
}
protected Hook optional() {
mOptional = true;
return this;
}
protected Hook obsolete() {
mObsolete = true;
return this;
}
public void annotate(String text) {
mAnnotation = text;
}
// Getters
public String getRestrictionName() {
return mRestrictionName;
}
public String getName() {
return mMethodName;
}
public String[] getPermissions() {
return mPermissions;
}
public boolean isAvailable() {
if (mObsolete)
return false;
if (Build.VERSION.SDK_INT < mSdkFrom)
return false;
if (Build.VERSION.SDK_INT > mSdkTo)
return false;
if (mAOSPSdk > 0 && !isAOSP(mAOSPSdk))
return false;
if (mNotAOSPSdk > 0 && isAOSP(mNotAOSPSdk))
return false;
return true;
}
public static boolean isAOSP(int sdk) {
if (!PrivacyManager.cVersion3)
return false;
if (Build.VERSION.SDK_INT >= sdk) {
if ("true".equals(System.getenv("XPrivacy.AOSP")))
return true;
if (Build.DISPLAY == null || Build.HOST == null)
return false;
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
// @formatter:off
return (
isAOSP() ||
isCyanogenMod() ||
isOmni() ||
isMIUI() ||
isSlim() ||
isParanoidAndroid() ||
isCarbon() ||
isDirtyUnicorns() ||
isLiquidSmooth() ||
isAndroidRevolutionHD() ||
isMahdi() ||
isOmega()
);
// @formatter:on
else
return isAOSP();
} else
return false;
}
public static boolean isAOSP() {
return Build.HOST.endsWith(".google.com");
}
public static boolean isCyanogenMod() {
return Build.HOST.equals("cyanogenmod") || Build.DISPLAY.startsWith("cm_");
}
public static boolean isOmni() {
return Build.DISPLAY.startsWith("slim");
}
public static boolean isMIUI() {
return Build.HOST.equals("xiaomi");
}
public static boolean isSlim() {
return Build.DISPLAY.startsWith("omni");
}
public static boolean isParanoidAndroid() {
return Build.HOST.startsWith("paranoid") || Build.DISPLAY.startsWith("pa_");
}
public static boolean isCarbon() {
return Build.DISPLAY.startsWith("carbon");
}
public static boolean isDirtyUnicorns() {
return Build.DISPLAY.startsWith("du_");
}
public static boolean isLiquidSmooth() {
return Build.DISPLAY.startsWith("liquid_");
}
public static boolean isAndroidRevolutionHD() {
return Build.DISPLAY.startsWith("Android Revolution HD");
}
public static boolean isMahdi() {
return Build.HOST.startsWith("mahdi");
}
public static boolean isOmega() {
return Build.DISPLAY.startsWith("Omega");
}
public Version getFrom() {
return mFrom;
}
public String getReplacedRestriction() {
return mReplacedRestriction;
}
public String getReplacedMethod() {
return mReplacedMethod;
}
@SuppressLint("FieldGetter")
public boolean isDangerous() {
String name = String.format("%s.%s.%s", PrivacyManager.cSettingDangerous, this.getRestrictionName(),
this.getName());
return PrivacyManager.getSettingBool(0, name, mDangerous);
}
public boolean isDangerousDefined() {
return mDangerous;
}
public boolean isRestartRequired() {
return mRestart;
}
public boolean hasUsageData() {
return !mNoUsageData;
}
public boolean canOnDemand() {
return !mNoOnDemand;
}
public String whitelist() {
return mWhitelist;
}
public boolean shouldNotify() {
return mNotify;
}
public boolean isUnsafe() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP)
return false;
if (PrivacyManager.cVersion3)
return mUnsafe;
else
return false;
}
public boolean isOptional() {
return mOptional;
}
public String getAnnotation() {
return mAnnotation;
}
// Comparison
@Override
public int hashCode() {
return (mRestrictionName.hashCode() ^ mMethodName.hashCode());
}
@Override
public boolean equals(Object obj) {
Hook other = (Hook) obj;
return (mRestrictionName.equals(other.mRestrictionName) && mMethodName.equals(other.mMethodName));
}
@Override
public int compareTo(Hook another) {
int x = mRestrictionName.compareTo(another.mRestrictionName);
return (x == 0 ? mMethodName.compareTo(another.mMethodName) : x);
}
@Override
public String toString() {
return String.format("%s/%s", mRestrictionName, mMethodName);
}
}