-
Notifications
You must be signed in to change notification settings - Fork 114
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
803 additions
and
884 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
24 changes: 15 additions & 9 deletions
24
app/src/main/java/com/github/ma1co/openmemories/tweak/BackupKeys.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,21 +1,27 @@ | ||
package com.github.ma1co.openmemories.tweak; | ||
|
||
public class BackupKeys { | ||
public static final int REC_LIMIT_H = 0x003c0373; | ||
public static final int REC_LIMIT_M = 0x003c0374; | ||
public static final int REC_LIMIT_S = 0x003c0375; | ||
public static final BackupProperty.Byte REC_LIMIT_H = new BackupProperty.Byte(0x003c0373); | ||
public static final BackupProperty.Byte REC_LIMIT_M = new BackupProperty.Byte(0x003c0374); | ||
public static final BackupProperty.Byte REC_LIMIT_S = new BackupProperty.Byte(0x003c0375); | ||
public static final BackupProperty.CompoundProperty<Integer> REC_LIMIT = new BackupProperty.CompoundProperty<>(Integer[].class, new BackupProperty.Byte[] { | ||
REC_LIMIT_H, | ||
REC_LIMIT_M, | ||
REC_LIMIT_S, | ||
}); | ||
|
||
public static final int REC_LIMIT_4K = 0x003c04b6; | ||
public static final BackupProperty.Short REC_LIMIT_4K = new BackupProperty.Short(0x003c04b6); | ||
|
||
private static final int LANGUAGE_ACTIVE_FIRST = 0x010d008f; | ||
private static final int LANGUAGE_ACTIVE_COUNT = 35; | ||
public static final int[] LANGUAGE_ACTIVE_LIST; | ||
|
||
public static final BackupProperty.Byte[] LANGUAGE_ACTIVE_LIST; | ||
public static final BackupProperty.CompoundProperty<Integer> LANGUAGE_ACTIVE; | ||
static { | ||
LANGUAGE_ACTIVE_LIST = new int[LANGUAGE_ACTIVE_COUNT]; | ||
LANGUAGE_ACTIVE_LIST = new BackupProperty.Byte[LANGUAGE_ACTIVE_COUNT]; | ||
for (int i = 0; i < LANGUAGE_ACTIVE_COUNT; i++) | ||
LANGUAGE_ACTIVE_LIST[i] = LANGUAGE_ACTIVE_FIRST + i; | ||
LANGUAGE_ACTIVE_LIST[i] = new BackupProperty.Byte(LANGUAGE_ACTIVE_FIRST + i); | ||
LANGUAGE_ACTIVE = new BackupProperty.CompoundProperty<>(Integer[].class, LANGUAGE_ACTIVE_LIST); | ||
} | ||
|
||
public static final int PAL_NTSC_SELECTOR_ENABLED = 0x01070148; | ||
public static final BackupProperty.Byte PAL_NTSC_SELECTOR_ENABLED = new BackupProperty.Byte(0x01070148); | ||
} |
200 changes: 200 additions & 0 deletions
200
app/src/main/java/com/github/ma1co/openmemories/tweak/BackupProperty.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
package com.github.ma1co.openmemories.tweak; | ||
|
||
import java.lang.reflect.Array; | ||
import java.util.Arrays; | ||
|
||
public abstract class BackupProperty<T> { | ||
public static class BackupException extends Exception { | ||
public BackupException(String message) { | ||
super(message); | ||
} | ||
} | ||
|
||
public static class BackupProtectionException extends BackupException { | ||
public BackupProtectionException() { | ||
super("Cannot change settings because protection is active. Please disable protection and try again."); | ||
} | ||
} | ||
|
||
public static class Byte extends BaseProperty<Integer> { | ||
public Byte(int id) { | ||
super(id, Integer.class, 1); | ||
} | ||
|
||
@Override | ||
protected byte[] toBytes(Integer value) { | ||
return new byte[] {(byte) (int) value}; | ||
} | ||
|
||
@Override | ||
protected Integer fromBytes(byte[] value) { | ||
return (int) value[0]; | ||
} | ||
} | ||
|
||
public static class Short extends BaseProperty<Integer> { | ||
public Short(int id) { | ||
super(id, Integer.class, 2); | ||
} | ||
|
||
@Override | ||
protected byte[] toBytes(Integer value) { | ||
return new byte[] {(byte) (int) value, (byte) (value >> 8)}; | ||
} | ||
|
||
@Override | ||
protected Integer fromBytes(byte[] value) { | ||
return (value[0] & 0xff) | value[1] << 8; | ||
} | ||
} | ||
|
||
public static abstract class BaseProperty<T> extends BackupProperty<T> { | ||
private final int id; | ||
private final int size; | ||
|
||
public BaseProperty(int id, Class<T> type, int size) { | ||
super(type); | ||
this.id = id; | ||
this.size = size; | ||
} | ||
|
||
public int getId() { | ||
return id; | ||
} | ||
|
||
public int getSize() { | ||
return size; | ||
} | ||
|
||
@Override | ||
public boolean exists() { | ||
try { | ||
int size = Backup.getSize(id); | ||
if (size != this.size) { | ||
Logger.error("BaseProperty.exists", String.format("%s has wrong size: %d instead of %d", this, size, this.size)); | ||
return false; | ||
} | ||
return true; | ||
} catch (NativeException e) { | ||
Logger.info("BaseProperty.exists", String.format("%s does not exist", this)); | ||
return false; | ||
} | ||
} | ||
|
||
public boolean isReadOnly() throws BackupException { | ||
try { | ||
return Backup.isReadOnly(id); | ||
} catch (NativeException e) { | ||
Logger.error("BaseProperty.isReadOnly", String.format("error reading %s", this), e); | ||
throw new BackupException("Read failed"); | ||
} | ||
} | ||
|
||
@Override | ||
public T getValue() throws BackupException { | ||
try { | ||
return fromBytes(Backup.getValue(id)); | ||
} catch (NativeException e) { | ||
Logger.error("BaseProperty.getValue", String.format("error reading %s", this), e); | ||
throw new BackupException("Read failed"); | ||
} | ||
} | ||
|
||
@Override | ||
public void setValue(T value) throws BackupException { | ||
try { | ||
Backup.setValue(id, toBytes(value)); | ||
} catch (NativeException e) { | ||
if (isReadOnly()) { | ||
Logger.info("BaseProperty.setValue", String.format("%s is protected", this)); | ||
throw new BackupProtectionException(); | ||
} else { | ||
Logger.error("BaseProperty.setValue", String.format("error writing %s", this), e); | ||
throw new BackupException("Write failed"); | ||
} | ||
} | ||
} | ||
|
||
protected abstract byte[] toBytes(T value); | ||
|
||
protected abstract T fromBytes(byte[] value); | ||
|
||
@Override | ||
public String toString() { | ||
return String.format("backup property 0x%x", id); | ||
} | ||
} | ||
|
||
public static class CompoundProperty<T> extends BackupProperty<T[]> { | ||
private final BaseProperty<T>[] properties; | ||
|
||
public CompoundProperty(Class<T[]> type, BaseProperty<T>[] properties) { | ||
super(type); | ||
this.properties = properties; | ||
} | ||
|
||
public BaseProperty<T>[] getProperties() { | ||
return properties; | ||
} | ||
|
||
@Override | ||
public boolean exists() { | ||
for (BaseProperty<T> property : properties) { | ||
if (!property.exists()) | ||
return false; | ||
} | ||
return true; | ||
} | ||
|
||
@Override | ||
public T[] getValue() throws BackupException { | ||
@SuppressWarnings("unchecked") | ||
T[] values = (T[]) Array.newInstance(getType().getComponentType(), properties.length); | ||
for (int i = 0; i < properties.length; i++) | ||
values[i] = properties[i].getValue(); | ||
return values; | ||
} | ||
|
||
@Override | ||
public void setValue(T[] value) throws BackupException { | ||
if (value.length != properties.length) | ||
throw new IllegalArgumentException("Wrong array length"); | ||
for (int i = 0; i < properties.length; i++) | ||
properties[i].setValue(value[i]); | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
StringBuilder sb = new StringBuilder(); | ||
sb.append("compound backup property ["); | ||
boolean first = true; | ||
for (BaseProperty<T> property : properties) { | ||
if (!first) | ||
sb.append(", "); | ||
sb.append(String.format("0x%x", property.getId())); | ||
first = false; | ||
} | ||
sb.append("]"); | ||
return sb.toString(); | ||
} | ||
} | ||
|
||
private final Class<T> type; | ||
|
||
public BackupProperty(Class<T> type) { | ||
this.type = type; | ||
} | ||
|
||
public Class<T> getType() { | ||
return type; | ||
} | ||
|
||
public abstract boolean exists(); | ||
public abstract T getValue() throws BackupException; | ||
public abstract void setValue(T value) throws BackupException; | ||
|
||
public boolean valueEquals(T correctValue) throws BackupException { | ||
T value = getValue(); | ||
return (type.isArray() && Arrays.equals((Object[]) correctValue, (Object[]) value)) || correctValue.equals(value); | ||
} | ||
} |
77 changes: 77 additions & 0 deletions
77
app/src/main/java/com/github/ma1co/openmemories/tweak/BackupSwitchAdapter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
package com.github.ma1co.openmemories.tweak; | ||
|
||
public abstract class BackupSwitchAdapter<T> implements ItemActivity.SwitchItem.Adapter { | ||
public static class ConstantImpl<T> extends BackupSwitchAdapter<T> { | ||
private final T offValue; | ||
private final T onValue; | ||
|
||
public ConstantImpl(BackupProperty<T> property, T offValue, T onValue) { | ||
super(property, false); | ||
this.offValue = offValue; | ||
this.onValue = onValue; | ||
} | ||
|
||
@Override | ||
public T getOffValue() { | ||
return offValue; | ||
} | ||
|
||
@Override | ||
public T getOnValue() { | ||
return onValue; | ||
} | ||
} | ||
|
||
private final BackupProperty<T> property; | ||
private final boolean allowOtherValues; | ||
|
||
public BackupSwitchAdapter(BackupProperty<T> property, boolean allowOtherValues) { | ||
this.property = property; | ||
this.allowOtherValues = allowOtherValues; | ||
} | ||
|
||
public BackupProperty<T> getProperty() { | ||
return property; | ||
} | ||
|
||
public abstract T getOffValue() throws BackupProperty.BackupException; | ||
public abstract T getOnValue() throws BackupProperty.BackupException; | ||
|
||
@Override | ||
public boolean isAvailable() { | ||
if (!property.exists()) | ||
return false; | ||
if (!allowOtherValues) { | ||
try { | ||
if (!property.valueEquals(getOffValue()) && !property.valueEquals(getOnValue())) { | ||
Logger.error("BackupSwitchAdapter.isAvailable", String.format("%s has unknown value", property)); | ||
return false; | ||
} | ||
} catch (BackupProperty.BackupException e) { | ||
Logger.error("BackupSwitchAdapter.isAvailable", String.format("cannot compare value of %s", property), e); | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
|
||
@Override | ||
public boolean isEnabled() { | ||
try { | ||
return property.valueEquals(getOnValue()); | ||
} catch (BackupProperty.BackupException e) { | ||
Logger.error("BackupSwitchAdapter.isEnabled", String.format("cannot compare value of %s", property), e); | ||
return false; | ||
} | ||
} | ||
|
||
@Override | ||
public void setEnabled(boolean enabled) throws BackupProperty.BackupException { | ||
property.setValue(enabled ? getOnValue() : getOffValue()); | ||
} | ||
|
||
@Override | ||
public String getSummary() { | ||
return isEnabled() ? "Enabled" : "Disabled"; | ||
} | ||
} |
Oops, something went wrong.