Skip to content

Commit

Permalink
Implemented "changed" property for boolean flags
Browse files Browse the repository at this point in the history
In the "Boolean Mods" section, now the switch cards that have been modified and have a value different from the default one are displayed with a colored background.
  • Loading branch information
jacopotediosi committed May 26, 2023
1 parent 6970162 commit 233cf6b
Show file tree
Hide file tree
Showing 5 changed files with 128 additions and 49 deletions.
89 changes: 62 additions & 27 deletions app/src/main/aidl/com/jacopomii/gappsmod/ICoreRootService.aidl
Original file line number Diff line number Diff line change
Expand Up @@ -4,92 +4,127 @@ interface ICoreRootService {
IBinder getFileSystemService();

/**
* Query the GMS and Vending Phenotype DBs to get a list of all package names that have at least one Flag set.
* Query the GMS and Vending Phenotype DBs to get a list of all package names that have at least
* one Flag set.
*
* @return a {@code HashMap} in the format "Phenotype package name" => "Android package name".
*/
Map phenotypeDBGetAllPackageNames();

/**
* Query the GMS and Vending Phenotype DBs to get a list of all package names that have at least one Flag overridden.
* Query the GMS and Vending Phenotype DBs to get a list of all package names that have at least
* one Flag overridden.
*
* @return a {@code HashMap} in the format "Phenotype package name" => "Android package name".
*/
Map phenotypeDBGetAllOverriddenPackageNames();

/**
* Query the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) to get the Android package name corresponding to a given {@code phenotypePackageName}.
* Query the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) to get the
* Android package name corresponding to a given {@code phenotypePackageName}.
*
* @param phenotypePackageName the Phenotype package name for which the corresponding Android package name is to be returned.
* @return the Android package name corresponding to the specified {@code phenotypePackageName}. An empty string if the phenotypePackageName couldn't be found.
* @param phenotypePackageName the Phenotype package name for which the corresponding Android
* package name is to be returned.
* @return the Android package name corresponding to the specified {@code phenotypePackageName}.
* An empty string if the phenotypePackageName couldn't be found.
*/
String phenotypeDBGetAndroidPackageNameByPhenotypePackageName(in String phenotypePackageName);

/**
* Query the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}), selecting all the "overridden" or "normal" boolean flags for a given {@code phenotypePackageName}.
* Query the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}), selecting all
* the boolean flags for a given {@code phenotypePackageName}.
*
* @param phenotypePackageName the Phenotype (not Android) package name whose flags are to be returned.
* @return a {@code HashMap} in the format "flag name" => "flag value, overrided or not".
* @param phenotypePackageName the Phenotype (not Android) package name whose flags are to be
* returned.
* @return a {@code HashMap} that uses the ({@code String}) flag name as the key.<br>
* For performance reasons, the value of this HashMap is a {@code List} structured as follows:<br>
* - Position 0 contains the {@code Boolean} value of the flag, giving priority to the value
* overridden in the FlagOverrides table, if present, over the one contained in the Flags table.<br>
* - Position 1 contains the {@code Boolean} value "changed", which is {@code true} if and only
* if the returned flag is overwritten in the FlagOverrides table and has a different value
* than the one contained in the Flags table; {@code false} otherwise.
*/
Map phenotypeDBGetBooleanFlagsOrOverridden(in String phenotypePackageName);

/**
* Query the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) to find out if all given {@code flags} are overridden for a given {@code phenotypePackageName}.
* Query the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) to find out if
* all given {@code flags} are overridden for a given {@code phenotypePackageName}.
* Please note that the fact that a flag is overridden only implies that it is present in the
* FlagOverrides table, and not that its value is different from what is indicated in the Flags
* table.
*
* @param phenotypePackageName the Phenotype (not Android) package name for which to check.
* @param flags the flags to check.
* @return {@code true} if all given {@code flags are overridden} for the given {@code phenotypePackageName}; {@code false} otherwise.
* @return {@code true} if all given {@code flags} are overridden for the given
* {@code phenotypePackageName}; {@code false} otherwise.
*/
boolean phenotypeDBAreAllFlagsOverridden(in String phenotypePackageName, in List<String> flags);

/**
* Remove all flag overrides from the GMS and Vending Phenotype DBs by truncating the FlagOverrides table.
* It also clears from the filesystem the Phenotype cache of all applications for which at least one flag was overridden.
* Remove all flag overrides from the GMS and Vending Phenotype DBs by truncating the
* FlagOverrides table.
* It also clears from the filesystem the Phenotype cache of all applications for which at least
* one flag was overridden.
*/
void phenotypeDBDeleteAllFlagOverrides();

/**
* Delete all flag overrides from the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to the given {@code phenotypePackageName}.
* Delete all flag overrides from the GMS/Vending Phenotype DB (based on the
* {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to
* the given {@code phenotypePackageName}.
*
* @param phenotypePackageName the Phenotype (not Android) package name for which to delete the flag overrides.
* @param phenotypePackageName the Phenotype (not Android) package name for which to delete the
* flag overrides.
*/
void phenotypeDBDeleteAllFlagOverridesByPhenotypePackageName(in String phenotypePackageName);

/**
* Delete a given list of flag overrides from the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to the given {@code phenotypePackageName}.
* Delete a given list of flag overrides from the GMS/Vending Phenotype DB (based on the
* {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to
* the given {@code phenotypePackageName}.
*
* @param phenotypePackageName the Phenotype (not Android) package name for which to delete the flag overrides.
* @param phenotypePackageName the Phenotype (not Android) package name for which to delete the
* flag overrides.
* @param flags the list of flags to delete.
*/
void phenotypeDBDeleteFlagOverrides(in String phenotypePackageName, in List<String> flags);

/**
* Override the value of a boolean flag in the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to the given {@code phenotypePackageName}.
* Override the value of a boolean flag in the GMS/Vending Phenotype DB (based on the
* {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to
* the given {@code phenotypePackageName}.
*
* @param phenotypePackageName the Phenotype (not Android) package name for which to override the flag.
* @param phenotypePackageName the Phenotype (not Android) package name for which to override
* the flag.
* @param flag the name of the flag to override.
* @param value the value to override the flag with.
*/
void phenotypeDBOverrideBooleanFlag(in String phenotypePackageName, in String flag, in boolean value);

/**
* Override the value of an extension flag in the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to the given {@code phenotypePackageName}.
* Override the value of an extension flag in the GMS/Vending Phenotype DB (based on the
* {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to
* the given {@code phenotypePackageName}.
*
* @param phenotypePackageName the Phenotype (not Android) package name for which to override the flag.
* @param phenotypePackageName the Phenotype (not Android) package name for which to override
* the flag.
* @param flag the name of the flag to override.
* @param value the value to override the flag with.
*/
void phenotypeDBOverrideExtensionFlag(in String phenotypePackageName, in String flag, in byte[] value);

/**
* Override the value of a string flag in the GMS/Vending Phenotype DB (based on the {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to the given {@code phenotypePackageName}.
* Override the value of a string flag in the GMS/Vending Phenotype DB (based on the
* {@code phenotypePackageName}) for a given {@code phenotypePackageName}.
* It also clears from the filesystem the Phenotype cache of the application corresponding to
* the given {@code phenotypePackageName}.
*
* @param phenotypePackageName the Phenotype (not Android) package name for which to override the flag.
* @param phenotypePackageName the Phenotype (not Android) package name for which to override
* the flag.
* @param flag the name of the flag to override.
* @param value the value to override the flag with.
*/
Expand Down
12 changes: 11 additions & 1 deletion app/src/main/java/com/jacopomii/gappsmod/data/BooleanFlag.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,12 @@
public class BooleanFlag {
private final String mFlagName;
private boolean mFlagValue;
private boolean mFlagOverriddenAndChanged;

public BooleanFlag(String flagName, boolean flagValue) {
public BooleanFlag(String flagName, boolean flagValue, boolean flagOverriddenAndChanged) {
mFlagName = flagName;
mFlagValue = flagValue;
mFlagOverriddenAndChanged = flagOverriddenAndChanged;
}

public String getFlagName() {
Expand All @@ -20,4 +22,12 @@ public boolean getFlagValue() {
public void setFlagValue(boolean flagValue) {
mFlagValue = flagValue;
}

public void setFlagOverriddenAndChanged(boolean flagOverriddenAndChanged) {
mFlagOverriddenAndChanged = flagOverriddenAndChanged;
}

public boolean getFlagOverriddenAndChanged() {
return mFlagOverriddenAndChanged;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@

import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
Expand Down Expand Up @@ -100,7 +101,7 @@ public String phenotypeDBGetAndroidPackageNameByPhenotypePackageName(String phen
}

@Override
public Map<String, Boolean> phenotypeDBGetBooleanFlagsOrOverridden(String phenotypePackageName) {
public Map<String, List<Object>> phenotypeDBGetBooleanFlagsOrOverridden(String phenotypePackageName) {
return CoreRootService.this.phenotypeDBGetBooleanFlagsOrOverridden(phenotypePackageName);
}

Expand Down Expand Up @@ -217,22 +218,29 @@ private String phenotypeDBGetAndroidPackageNameByPhenotypePackageName(String phe
return "";
}

private Map<String, Boolean> phenotypeDBGetBooleanFlagsOrOverridden(String phenotypePackageName) {
HashMap<String, Boolean> map = new HashMap<>();
private Map<String, List<Object>> phenotypeDBGetBooleanFlagsOrOverridden(String phenotypePackageName) {
Map<String, List<Object>> map = new HashMap<>();

SQLiteDatabase phenotypeDB = getPhenotypeDBByPhenotypePackageName(phenotypePackageName);
String sql = "SELECT DISTINCT name,boolVal " +
"FROM Flags " +
"WHERE packageName=? AND name NOT IN (SELECT name FROM FlagOverrides WHERE packageName=?) AND user='' AND boolVal!='NULL' " +
"UNION ALL " +
"SELECT DISTINCT name,boolVal FROM FlagOverrides " +
"WHERE packageName=? AND user='' AND boolVal!='NULL'";
String[] selectionArgs = {phenotypePackageName, phenotypePackageName, phenotypePackageName};
String sql = "SELECT DISTINCT f.name AS name, COALESCE(fo.boolVal, f.boolVal) AS boolVal, CASE WHEN fo.boolVal != f.boolVal THEN 1 ELSE 0 END AS changed " +
"FROM Flags f " +
"LEFT JOIN FlagOverrides fo ON f.packageName = fo.packageName AND f.name = fo.name " +
"WHERE f.packageName = ? AND f.user = '' AND (f.boolVal IS NOT NULL OR fo.boolVal IS NOT NULL)" +
"UNION ALL " +
"SELECT DISTINCT fo.name AS name, fo.boolVal, 1 AS changed " +
"FROM FlagOverrides fo " +
"LEFT JOIN Flags f ON f.packageName = fo.packageName AND f.name = fo.name " +
"WHERE fo.packageName = ? AND f.name IS NULL AND fo.user = '' AND fo.boolVal IS NOT NULL";
String[] selectionArgs = {phenotypePackageName, phenotypePackageName};

try {
try (Cursor cursor = phenotypeDB.rawQuery(sql, selectionArgs)) {
while (cursor.moveToNext())
map.put(cursor.getString(0), cursor.getInt(1) != 0);
while (cursor.moveToNext()) {
String name = cursor.getString(0);
Boolean boolVal = cursor.getInt(1) != 0;
Boolean changed = cursor.getInt(2) != 0;
map.put(name, Arrays.asList(boolVal, changed));
}
}
} catch (Exception e) {
e.printStackTrace();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

import android.annotation.SuppressLint;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.os.RemoteException;
import android.view.LayoutInflater;
import android.view.ViewGroup;
Expand All @@ -12,7 +14,9 @@
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.google.android.material.card.MaterialCardView;
import com.jacopomii.gappsmod.ICoreRootService;
import com.jacopomii.gappsmod.R;
import com.jacopomii.gappsmod.data.BooleanFlag;
import com.jacopomii.gappsmod.databinding.SwitchCardBinding;
import com.jacopomii.gappsmod.ui.view.ProgrammaticMaterialSwitch;
Expand Down Expand Up @@ -48,9 +52,14 @@ public void selectPhenotypePackageName(String phenotypePackageName) {

try {
mFlagsList = new ArrayList<>();
TreeMap<String, Boolean> map = new TreeMap<String, Boolean>(mCoreRootServiceIpc.phenotypeDBGetBooleanFlagsOrOverridden(phenotypePackageName));
for (Map.Entry<String, Boolean> flag : map.entrySet())
mFlagsList.add(new BooleanFlag(flag.getKey(), flag.getValue()));
TreeMap<String, List<Object>> map = new TreeMap<String, List<Object>>(mCoreRootServiceIpc.phenotypeDBGetBooleanFlagsOrOverridden(phenotypePackageName));
for (Map.Entry<String, List<Object>> flag : map.entrySet()) {
String flagName = flag.getKey();
List<Object> flagData = flag.getValue();
Boolean flagValue = (Boolean) flagData.get(0);
Boolean flagOverriddenAndChanged = (Boolean) flagData.get(1);
mFlagsList.add(new BooleanFlag(flagName, flagValue, flagOverriddenAndChanged));
}

if (mLastFilterPerformed != null) {
getFilter().filter(mLastFilterPerformed);
Expand All @@ -72,15 +81,19 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

// Set setOnCheckedChangeListener on list items
viewHolder.mSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
int position = viewHolder.getAdapterPosition();
int checkedPosition = viewHolder.getAdapterPosition();
BooleanFlag checkedBooleanFlag = mFlagsListFiltered.get(checkedPosition);
String checkedBooleanFlagName = checkedBooleanFlag.getFlagName();

mFlagsListFiltered.get(position).setFlagValue(isChecked);
checkedBooleanFlag.setFlagValue(isChecked);
try {
mCoreRootServiceIpc.phenotypeDBOverrideBooleanFlag(mPhenotypePackageName, mFlagsListFiltered.get(position).getFlagName(), isChecked);
mCoreRootServiceIpc.phenotypeDBOverrideBooleanFlag(mPhenotypePackageName, checkedBooleanFlagName, isChecked);
} catch (RemoteException e) {
e.printStackTrace();
}
notifyItemChanged(position);
checkedBooleanFlag.setFlagOverriddenAndChanged(!checkedBooleanFlag.getFlagOverriddenAndChanged());

notifyItemChanged(checkedPosition);
});

// Return viewHolder
Expand All @@ -89,11 +102,22 @@ public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {

@Override
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
// Get the boolean flag
BooleanFlag booleanFlag = mFlagsListFiltered.get(position);

// Update switch text
holder.mTextView.setText(mFlagsListFiltered.get(position).getFlagName());
holder.mTextView.setText(booleanFlag.getFlagName());

// Update the switch checked status without triggering any existing listener
holder.mSwitch.setCheckedProgrammatically(mFlagsListFiltered.get(position).getFlagValue());
holder.mSwitch.setCheckedProgrammatically(booleanFlag.getFlagValue());

// Change background color for cards containing overridden and changed flags
TypedArray typedArray = mContext.getTheme().obtainStyledAttributes(R.styleable.ViewStyle);
int colorSurface = typedArray.getColor(R.styleable.ViewStyle_colorSurface, Color.WHITE);
int colorSurfaceVariant = typedArray.getColor(R.styleable.ViewStyle_colorSecondaryContainer, Color.LTGRAY);
typedArray.recycle();
int cardBackgroundColor = booleanFlag.getFlagOverriddenAndChanged() ? colorSurfaceVariant : colorSurface;
((MaterialCardView) holder.itemView).setCardBackgroundColor(cardBackgroundColor);
}

@Override
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/res/values/attrs.xml
Original file line number Diff line number Diff line change
Expand Up @@ -14,5 +14,7 @@

<declare-styleable name="ViewStyle">
<attr name="colorError" format="color" />
<attr name="colorSurface" format="color" />
<attr name="colorSecondaryContainer" format="color" />
</declare-styleable>
</resources>

0 comments on commit 233cf6b

Please sign in to comment.