diff --git a/XposedLibrary/.classpath b/XposedLibrary/.classpath
new file mode 100644
index 0000000..a4763d1
--- /dev/null
+++ b/XposedLibrary/.classpath
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
diff --git a/XposedLibrary/.project b/XposedLibrary/.project
new file mode 100644
index 0000000..234cd0f
--- /dev/null
+++ b/XposedLibrary/.project
@@ -0,0 +1,33 @@
+
+
+ XposedLibrary
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/XposedLibrary/AndroidManifest.xml b/XposedLibrary/AndroidManifest.xml
new file mode 100644
index 0000000..9803197
--- /dev/null
+++ b/XposedLibrary/AndroidManifest.xml
@@ -0,0 +1,4 @@
+
+
+
\ No newline at end of file
diff --git a/XposedLibrary/XposedBridgeApi.jar b/XposedLibrary/XposedBridgeApi.jar
new file mode 100644
index 0000000..b7631cb
Binary files /dev/null and b/XposedLibrary/XposedBridgeApi.jar differ
diff --git a/XposedLibrary/project.properties b/XposedLibrary/project.properties
new file mode 100644
index 0000000..fec2d61
--- /dev/null
+++ b/XposedLibrary/project.properties
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-15
+android.library=true
diff --git a/XposedLibrary/res/layout/preference_valueseekbar_extension.xml b/XposedLibrary/res/layout/preference_valueseekbar_extension.xml
new file mode 100644
index 0000000..8bc7271
--- /dev/null
+++ b/XposedLibrary/res/layout/preference_valueseekbar_extension.xml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/XposedLibrary/src/de/robv/android/xposed/library/ui/IntegerListPreference.java b/XposedLibrary/src/de/robv/android/xposed/library/ui/IntegerListPreference.java
new file mode 100644
index 0000000..9b127dc
--- /dev/null
+++ b/XposedLibrary/src/de/robv/android/xposed/library/ui/IntegerListPreference.java
@@ -0,0 +1,63 @@
+package de.robv.android.xposed.library.ui;
+
+import android.content.Context;
+import android.content.SharedPreferences;
+import android.preference.ListPreference;
+import android.util.AttributeSet;
+
+public class IntegerListPreference extends ListPreference {
+ public IntegerListPreference(Context context) {
+ super(context);
+ }
+
+ public IntegerListPreference(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void setValue(String value) {
+ super.setValue(value);
+ notifyChanged();
+ }
+
+ @Override
+ protected boolean persistString(String value) {
+ if (value == null)
+ return false;
+
+ return persistInt(getIntValue(value));
+ }
+
+ @Override
+ protected String getPersistedString(String defaultReturnValue) {
+ SharedPreferences pref = getPreferenceManager().getSharedPreferences();
+ String key = getKey();
+ if (!shouldPersist() || !pref.contains(key))
+ return defaultReturnValue;
+
+ return String.valueOf(pref.getInt(key, 0));
+ }
+
+ @Override
+ public int findIndexOfValue(String value) {
+ CharSequence[] entryValues = getEntryValues();
+ int intValue = getIntValue(value);
+ if (value != null && entryValues != null) {
+ for (int i = entryValues.length - 1; i >= 0; i--) {
+ if (getIntValue(entryValues[i].toString()) == intValue) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ }
+
+ public static int getIntValue(String value) {
+ if (value == null)
+ return 0;
+
+ return (int)((value.startsWith("0x"))
+ ? Long.parseLong(value.substring(2), 16)
+ : Long.parseLong(value));
+ }
+}
diff --git a/XposedLibrary/src/de/robv/android/xposed/library/ui/ListPreferenceFixedSummary.java b/XposedLibrary/src/de/robv/android/xposed/library/ui/ListPreferenceFixedSummary.java
new file mode 100644
index 0000000..d85dc0a
--- /dev/null
+++ b/XposedLibrary/src/de/robv/android/xposed/library/ui/ListPreferenceFixedSummary.java
@@ -0,0 +1,21 @@
+package de.robv.android.xposed.library.ui;
+
+import android.content.Context;
+import android.preference.ListPreference;
+import android.util.AttributeSet;
+
+public class ListPreferenceFixedSummary extends ListPreference {
+ public ListPreferenceFixedSummary(Context context) {
+ super(context);
+ }
+
+ public ListPreferenceFixedSummary(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ public void setValue(String value) {
+ super.setValue(value);
+ notifyChanged();
+ }
+}
diff --git a/XposedLibrary/src/de/robv/android/xposed/library/ui/ValueSeekBarPreference.java b/XposedLibrary/src/de/robv/android/xposed/library/ui/ValueSeekBarPreference.java
new file mode 100644
index 0000000..bd5f9a1
--- /dev/null
+++ b/XposedLibrary/src/de/robv/android/xposed/library/ui/ValueSeekBarPreference.java
@@ -0,0 +1,265 @@
+/*
+ * Copyright (C) 2011 The Android Open Source 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 de.robv.android.xposed.library.ui;
+
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.preference.Preference;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.SeekBar;
+import android.widget.SeekBar.OnSeekBarChangeListener;
+import android.widget.TextView;
+import de.robv.android.xposed.library.R;
+
+public class ValueSeekBarPreference extends Preference implements OnSeekBarChangeListener {
+
+ private int mProgress;
+ private int mStep;
+ private int mMin;
+ private int mMax;
+ private String valueDisplayFormat;
+ private boolean mTrackingTouch;
+ private TextView tvValue;
+
+ public ValueSeekBarPreference(
+ Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ setStep(attrs.getAttributeIntValue(null, "step", 1));
+ setMin(attrs.getAttributeIntValue(null, "min", 0));
+ setMax(attrs.getAttributeIntValue(null, "max", 100));
+ valueDisplayFormat = attrs.getAttributeValue(null, "displayFormat");
+ if (valueDisplayFormat == null)
+ valueDisplayFormat = "%d";
+ }
+
+ public ValueSeekBarPreference(Context context, AttributeSet attrs) {
+ this(context, attrs, android.R.attr.preferenceStyle);
+ }
+
+ public ValueSeekBarPreference(Context context) {
+ this(context, null);
+ }
+
+ @Override
+ protected View onCreateView(ViewGroup parent) {
+ ViewGroup originalView = (ViewGroup) super.onCreateView(parent);
+
+ final LayoutInflater layoutInflater =
+ (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+
+ ViewGroup newlayout = (ViewGroup) layoutInflater.inflate(R.layout.preference_valueseekbar_extension, null);
+ newlayout.addView(originalView, 0);
+
+ tvValue = (TextView) newlayout.findViewById(R.id.valueseekbar_preference_value);
+
+ return newlayout;
+ }
+
+ @Override
+ protected void onBindView(View view) {
+ super.onBindView(view);
+ SeekBar seekBar = (SeekBar) view.findViewById(R.id.valueseekbar_preference_seekbar);
+ seekBar.setOnSeekBarChangeListener(this);
+ seekBar.setMax((mMax - mMin) / mStep);
+ seekBar.setProgress((mProgress - mMin) / mStep);
+ tvValue.setText(String.format(valueDisplayFormat, mProgress));
+ seekBar.setEnabled(isEnabled());
+ }
+
+ @Override
+ protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
+ setProgress(restoreValue ? getPersistedInt(mProgress)
+ : (Integer) defaultValue);
+ }
+
+ @Override
+ protected Object onGetDefaultValue(TypedArray a, int index) {
+ return a.getInt(index, 0);
+ }
+
+ public void setStep(int step) {
+ if (step != mStep) {
+ mStep = step;
+ notifyChanged();
+ }
+ }
+
+ public void setMin(int min) {
+ if (min != mMin) {
+ mMin = min;
+ notifyChanged();
+ }
+ }
+
+ public void setMax(int max) {
+ if (max != mMax) {
+ mMax = max;
+ notifyChanged();
+ }
+ }
+
+ public void setProgress(int progress) {
+ setProgress(progress, true);
+ }
+
+ private void setProgress(int progress, boolean notifyChanged) {
+ if (progress > mMax) {
+ progress = mMax;
+ }
+ if (progress < mMin) {
+ progress = mMin;
+ }
+ if (progress != mProgress) {
+ mProgress = progress;
+ persistInt(progress);
+ if (notifyChanged) {
+ notifyChanged();
+ }
+ }
+ }
+
+ public int getProgress() {
+ return mProgress;
+ }
+
+ /**
+ * Persist the seekBar's progress value if callChangeListener
+ * returns true, otherwise set the seekBar's progress to the stored value
+ */
+ void syncProgress(SeekBar seekBar) {
+ int progress = seekBar.getProgress() * mStep + mMin;
+ if (progress != mProgress) {
+ if (callChangeListener(progress)) {
+ setProgress(progress, false);
+ } else {
+ seekBar.setProgress((mProgress - mMin) / mStep);
+ }
+ }
+ }
+
+ @Override
+ public void onProgressChanged(
+ SeekBar seekBar, int progress, boolean fromUser) {
+ if (fromUser && !mTrackingTouch) {
+ syncProgress(seekBar);
+ }
+ tvValue.setText(String.format(valueDisplayFormat, progress * mStep + mMin));
+ }
+
+ @Override
+ public void onStartTrackingTouch(SeekBar seekBar) {
+ mTrackingTouch = true;
+ }
+
+ @Override
+ public void onStopTrackingTouch(SeekBar seekBar) {
+ mTrackingTouch = false;
+ if (seekBar.getProgress() * mStep + mMin != mProgress) {
+ syncProgress(seekBar);
+ }
+ }
+
+ @Override
+ protected Parcelable onSaveInstanceState() {
+ /*
+ * Suppose a client uses this preference type without persisting. We
+ * must save the instance state so it is able to, for example, survive
+ * orientation changes.
+ */
+
+ final Parcelable superState = super.onSaveInstanceState();
+ if (isPersistent()) {
+ // No need to save instance state since it's persistent
+ return superState;
+ }
+
+ // Save the instance state
+ final SavedState myState = new SavedState(superState);
+ myState.progress = mProgress;
+ myState.max = mMax;
+ return myState;
+ }
+
+ @Override
+ protected void onRestoreInstanceState(Parcelable state) {
+ if (!state.getClass().equals(SavedState.class)) {
+ // Didn't save state for us in onSaveInstanceState
+ super.onRestoreInstanceState(state);
+ return;
+ }
+
+ // Restore the instance state
+ SavedState myState = (SavedState) state;
+ super.onRestoreInstanceState(myState.getSuperState());
+ mProgress = myState.progress;
+ mStep = myState.step;
+ mMin = myState.min;
+ mMax = myState.max;
+ notifyChanged();
+ }
+
+ /**
+ * SavedState, a subclass of {@link BaseSavedState}, will store the state
+ * of MyPreference, a subclass of Preference.
+ *
+ * It is important to always call through to super methods.
+ */
+ private static class SavedState extends BaseSavedState {
+ int progress;
+ int step;
+ int min;
+ int max;
+
+ public SavedState(Parcel source) {
+ super(source);
+
+ // Restore the click counter
+ progress = source.readInt();
+ max = source.readInt();
+ }
+
+ @Override
+ public void writeToParcel(Parcel dest, int flags) {
+ super.writeToParcel(dest, flags);
+
+ // Save the click counter
+ dest.writeInt(progress);
+ dest.writeInt(max);
+ }
+
+ public SavedState(Parcelable superState) {
+ super(superState);
+ }
+
+ @SuppressWarnings("unused")
+ public static final Parcelable.Creator CREATOR =
+ new Parcelable.Creator() {
+ public SavedState createFromParcel(Parcel in) {
+ return new SavedState(in);
+ }
+
+ public SavedState[] newArray(int size) {
+ return new SavedState[size];
+ }
+ };
+ }
+}
diff --git a/XposedTweakbox/.classpath b/XposedTweakbox/.classpath
new file mode 100644
index 0000000..8564b5c
--- /dev/null
+++ b/XposedTweakbox/.classpath
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
diff --git a/XposedTweakbox/.project b/XposedTweakbox/.project
new file mode 100644
index 0000000..a4a7279
--- /dev/null
+++ b/XposedTweakbox/.project
@@ -0,0 +1,33 @@
+
+
+ XposedTweakbox
+
+
+
+
+
+ com.android.ide.eclipse.adt.ResourceManagerBuilder
+
+
+
+
+ com.android.ide.eclipse.adt.PreCompilerBuilder
+
+
+
+
+ org.eclipse.jdt.core.javabuilder
+
+
+
+
+ com.android.ide.eclipse.adt.ApkBuilder
+
+
+
+
+
+ com.android.ide.eclipse.adt.AndroidNature
+ org.eclipse.jdt.core.javanature
+
+
diff --git a/XposedTweakbox/.settings/org.eclipse.ltk.core.refactoring.prefs b/XposedTweakbox/.settings/org.eclipse.ltk.core.refactoring.prefs
new file mode 100644
index 0000000..8d75616
--- /dev/null
+++ b/XposedTweakbox/.settings/org.eclipse.ltk.core.refactoring.prefs
@@ -0,0 +1,3 @@
+#Tue May 01 17:10:08 CEST 2012
+eclipse.preferences.version=1
+org.eclipse.ltk.core.refactoring.enable.project.refactoring.history=false
diff --git a/XposedTweakbox/AndroidManifest.xml b/XposedTweakbox/AndroidManifest.xml
new file mode 100644
index 0000000..7431c57
--- /dev/null
+++ b/XposedTweakbox/AndroidManifest.xml
@@ -0,0 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/XposedTweakbox/assets/xposed_init b/XposedTweakbox/assets/xposed_init
new file mode 100644
index 0000000..d576fb1
--- /dev/null
+++ b/XposedTweakbox/assets/xposed_init
@@ -0,0 +1 @@
+de.robv.android.xposed.mods.tweakbox.XposedTweakbox
\ No newline at end of file
diff --git a/XposedTweakbox/logo.psd b/XposedTweakbox/logo.psd
new file mode 100644
index 0000000..17bde70
Binary files /dev/null and b/XposedTweakbox/logo.psd differ
diff --git a/XposedTweakbox/project.properties b/XposedTweakbox/project.properties
new file mode 100644
index 0000000..216a553
--- /dev/null
+++ b/XposedTweakbox/project.properties
@@ -0,0 +1,15 @@
+# This file is automatically generated by Android Tools.
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED!
+#
+# This file must be checked in Version Control Systems.
+#
+# To customize properties used by the Ant build system edit
+# "ant.properties", and override values to adapt the script to your
+# project structure.
+#
+# To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
+#proguard.config=${sdk.dir}\tools\proguard\proguard-android.txt:proguard-project.txt
+
+# Project target.
+target=android-15
+android.library.reference.1=../XposedLibrary
diff --git a/XposedTweakbox/res/drawable-hdpi/ic_launcher.png b/XposedTweakbox/res/drawable-hdpi/ic_launcher.png
new file mode 100644
index 0000000..ce7afce
Binary files /dev/null and b/XposedTweakbox/res/drawable-hdpi/ic_launcher.png differ
diff --git a/XposedTweakbox/res/drawable-ldpi/ic_launcher.png b/XposedTweakbox/res/drawable-ldpi/ic_launcher.png
new file mode 100644
index 0000000..30e3aff
Binary files /dev/null and b/XposedTweakbox/res/drawable-ldpi/ic_launcher.png differ
diff --git a/XposedTweakbox/res/drawable-mdpi/ic_launcher.png b/XposedTweakbox/res/drawable-mdpi/ic_launcher.png
new file mode 100644
index 0000000..f790fb8
Binary files /dev/null and b/XposedTweakbox/res/drawable-mdpi/ic_launcher.png differ
diff --git a/XposedTweakbox/res/drawable-xhdpi/ic_launcher.png b/XposedTweakbox/res/drawable-xhdpi/ic_launcher.png
new file mode 100644
index 0000000..8acb262
Binary files /dev/null and b/XposedTweakbox/res/drawable-xhdpi/ic_launcher.png differ
diff --git a/XposedTweakbox/res/layout/settings.xml b/XposedTweakbox/res/layout/settings.xml
new file mode 100644
index 0000000..e4ba79a
--- /dev/null
+++ b/XposedTweakbox/res/layout/settings.xml
@@ -0,0 +1,20 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/XposedTweakbox/res/values/arrays.xml b/XposedTweakbox/res/values/arrays.xml
new file mode 100644
index 0000000..3464799
--- /dev/null
+++ b/XposedTweakbox/res/values/arrays.xml
@@ -0,0 +1,29 @@
+
+
+
+
+ - Do nothing
+ - Show classical recent apps list (icons only)
+ - Show new recent apps list (with thumbnails)
+
+
+ - 0
+ - 1
+ - 2
+
+
+ - Transparent
+ - Semi-transparent (25%)
+ - Semi-transparent (50%)
+ - Semi-transparent (75%)
+ - Default
+
+
+ - 0
+ - 0x3f000000
+ - 0x7f000000
+ - 0xbf000000
+ - 0xdeadbeef
+
+
+
\ No newline at end of file
diff --git a/XposedTweakbox/res/values/strings.xml b/XposedTweakbox/res/values/strings.xml
new file mode 100644
index 0000000..82ed282
--- /dev/null
+++ b/XposedTweakbox/res/values/strings.xml
@@ -0,0 +1,8 @@
+
+
+
+ Xposed Tweakbox
+ Tweakbox
+ Most of these modifications should be compatible with Samsung-stock-based ROMs and AOSP-based ROMs. Some might be compatible with CM9 as well.\nThe settings will be effective after the next reboot (or after restarting the SystemUI for status bar related settings).
+
+
\ No newline at end of file
diff --git a/XposedTweakbox/res/xml/preferences.xml b/XposedTweakbox/res/xml/preferences.xml
new file mode 100644
index 0000000..132126c
--- /dev/null
+++ b/XposedTweakbox/res/xml/preferences.xml
@@ -0,0 +1,90 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/VolumeKeysSkipTrack.java b/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/VolumeKeysSkipTrack.java
new file mode 100644
index 0000000..4677f7d
--- /dev/null
+++ b/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/VolumeKeysSkipTrack.java
@@ -0,0 +1,155 @@
+package de.robv.android.xposed.mods.tweakbox;
+
+import java.lang.reflect.AccessibleObject;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+
+import android.content.Context;
+import android.content.Intent;
+import android.os.Handler;
+import android.os.SystemClock;
+import android.view.KeyEvent;
+import android.view.ViewConfiguration;
+import de.robv.android.xposed.Callback;
+import de.robv.android.xposed.XposedBridge;
+
+// ported from https://github.com/CyanogenMod/android_frameworks_base/commit/fa0c6a58a44fd884d758d47eaa750c9c6476af1a
+public class VolumeKeysSkipTrack {
+ private static Method method_isMusicActive;
+ private static Field field_mContext;
+ private static Field field_mHandler;
+
+ private static boolean alsoForScreenOn;
+
+ private static boolean mIsLongPress = false;
+ // there can only be one
+ private static Object phoneWindowManager = null;
+
+ static void init(boolean alsoForScreenOn) {
+ try {
+ VolumeKeysSkipTrack.alsoForScreenOn = false; //alsoForScreenOn;
+
+ Class> classPhoneWindowManager = Class.forName("com.android.internal.policy.impl.PhoneWindowManager");
+ method_isMusicActive = classPhoneWindowManager.getDeclaredMethod("isMusicActive");
+
+ Method method_handleInterceptKeyBeforeQueueing = classPhoneWindowManager
+ .getDeclaredMethod("interceptKeyBeforeQueueing", KeyEvent.class, int.class, boolean.class);
+ XposedBridge.hookMethod(method_handleInterceptKeyBeforeQueueing, VolumeKeysSkipTrack.class, "handleInterceptKeyBeforeQueueing", Callback.PRIORITY_HIGHEST);
+
+ field_mContext = classPhoneWindowManager.getDeclaredField("mContext");
+ field_mHandler = classPhoneWindowManager.getDeclaredField("mHandler");
+
+ AccessibleObject.setAccessible(new AccessibleObject[] {
+ method_isMusicActive,
+ field_mContext,
+ field_mHandler,
+ }, true);
+ } catch (Exception e) { XposedBridge.log(e); }
+ }
+
+ @SuppressWarnings("unused")
+ private static Object handleInterceptKeyBeforeQueueing(Iterator iterator, Method method, Object thisObject, Object[] args) throws Throwable {
+ try {
+ final boolean isScreenOn = (Boolean) args[2];
+ if (!isScreenOn || alsoForScreenOn) {
+ final KeyEvent event = (KeyEvent) args[0];
+ final int keyCode = event.getKeyCode();
+ if ((keyCode == KeyEvent.KEYCODE_VOLUME_DOWN || keyCode == KeyEvent.KEYCODE_VOLUME_UP)
+ && (Boolean)method_isMusicActive.invoke(thisObject) == true) {
+ phoneWindowManager = thisObject;
+ if (event.getAction() == KeyEvent.ACTION_DOWN) {
+ mIsLongPress = false;
+ handleVolumeLongPress(keyCode);
+ return 0;
+ } else {
+ handleVolumeLongPressAbort();
+ if (mIsLongPress)
+ return 0;
+
+ // send an additional "key down" because the first one was eaten
+ // the "key up" is what we are just processing
+ Object[] newArgs = new Object[3];
+ newArgs[0] = new KeyEvent(KeyEvent.ACTION_DOWN, keyCode);
+ newArgs[1] = args[1];
+ newArgs[2] = args[2];
+ XposedBridge.invokeOriginalMethod(method, thisObject, newArgs);
+ }
+ }
+ }
+
+ } catch (Exception e) {
+ XposedBridge.log(e);
+ }
+ Object result = XposedBridge.callNext(iterator, method, thisObject, args);
+ return result;
+ }
+
+ /**
+ * When a volumeup-key longpress expires, skip songs based on key press
+ */
+ private static Runnable mVolumeUpLongPress = new Runnable() {
+ public void run() {
+ // set the long press flag to true
+ mIsLongPress = true;
+
+ // Shamelessly copied from Kmobs LockScreen controls, works for Pandora, etc...
+ sendMediaButtonEvent(KeyEvent.KEYCODE_MEDIA_NEXT);
+ };
+ };
+
+ /**
+ * When a volumedown-key longpress expires, skip songs based on key press
+ */
+ private static Runnable mVolumeDownLongPress = new Runnable() {
+ public void run() {
+ // set the long press flag to true
+ mIsLongPress = true;
+
+ // Shamelessly copied from Kmobs LockScreen controls, works for Pandora, etc...
+ sendMediaButtonEvent(KeyEvent.KEYCODE_MEDIA_PREVIOUS);
+ };
+ };
+
+ private static void sendMediaButtonEvent(int code) {
+ Context mContext = null;
+ try {
+ mContext = (Context) field_mContext.get(phoneWindowManager);
+ } catch (Exception e) {
+ XposedBridge.log(e);
+ }
+
+ long eventtime = SystemClock.uptimeMillis();
+ Intent keyIntent = new Intent(Intent.ACTION_MEDIA_BUTTON, null);
+ KeyEvent keyEvent = new KeyEvent(eventtime, eventtime, KeyEvent.ACTION_DOWN, code, 0);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ mContext.sendOrderedBroadcast(keyIntent, null);
+ keyEvent = KeyEvent.changeAction(keyEvent, KeyEvent.ACTION_UP);
+ keyIntent.putExtra(Intent.EXTRA_KEY_EVENT, keyEvent);
+ mContext.sendOrderedBroadcast(keyIntent, null);
+ }
+
+ private static void handleVolumeLongPress(int keycode) {
+ Handler mHandler = null;
+ try {
+ mHandler = (Handler) field_mHandler.get(phoneWindowManager);
+ } catch (Exception e) {
+ XposedBridge.log(e);
+ }
+
+ mHandler.postDelayed(keycode == KeyEvent.KEYCODE_VOLUME_UP ? mVolumeUpLongPress :
+ mVolumeDownLongPress, ViewConfiguration.getLongPressTimeout());
+ }
+
+ private static void handleVolumeLongPressAbort() {
+ Handler mHandler = null;
+ try {
+ mHandler = (Handler) field_mHandler.get(phoneWindowManager);
+ } catch (Exception e) {
+ XposedBridge.log(e);
+ }
+
+ mHandler.removeCallbacks(mVolumeUpLongPress);
+ mHandler.removeCallbacks(mVolumeDownLongPress);
+ }
+}
diff --git a/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/XposedTweakbox.java b/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/XposedTweakbox.java
new file mode 100644
index 0000000..0ecfcf2
--- /dev/null
+++ b/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/XposedTweakbox.java
@@ -0,0 +1,115 @@
+package de.robv.android.xposed.mods.tweakbox;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+import java.util.Iterator;
+
+import android.app.AndroidAppHelper;
+import android.content.SharedPreferences;
+import android.content.res.XResources;
+import android.graphics.PixelFormat;
+import android.graphics.drawable.ColorDrawable;
+import android.view.WindowManager;
+import de.robv.android.xposed.Callback;
+import de.robv.android.xposed.XposedBridge;
+
+
+public class XposedTweakbox {
+ public static final String MY_PACKAGE_NAME = "de.robv.android.xposed.mods.tweakbox";
+
+ public static void init(String startClassName) throws Exception {
+ if (startClassName != null)
+ return;
+
+ // we could save the preferences as static variable, but by fetching it everytime we use it,
+ // we have a change to apply settings immediately or when the app is restarted
+ SharedPreferences pref = AndroidAppHelper.getDefaultSharedPreferencesForPackage(MY_PACKAGE_NAME);
+
+ try {
+ if (pref.getBoolean("crt_off_effect", false)) {
+ XResources.setSystemWideReplacement("android", "bool", "config_animateScreenLights", false);
+ }
+ } catch (Exception e) { XposedBridge.log(e); }
+
+ try {
+ if (!pref.getBoolean("unplug_turns_screen_on", true)) {
+ XResources.setSystemWideReplacement("android", "bool", "config_unplugTurnsOnScreen", false);
+ }
+ } catch (Exception e) { XposedBridge.log(e); }
+
+ try {
+ XResources.setSystemWideReplacement("android", "integer", "config_longPressOnHomeBehavior", pref.getInt("long_home_press_behaviour", 2));
+ } catch (Exception e) { XposedBridge.log(e); }
+
+ try {
+ XResources.setSystemWideReplacement("android", "integer", "config_criticalBatteryWarningLevel", pref.getInt("low_battery_critical", 5));
+ XResources.setSystemWideReplacement("android", "integer", "config_lowBatteryWarningLevel", pref.getInt("low_battery_low", 15));
+ XResources.setSystemWideReplacement("android", "integer", "config_lowBatteryCloseWarningLevel", pref.getInt("low_battery_close", 20));
+ } catch (Exception e) { XposedBridge.log(e); }
+
+ XposedBridge.hookLoadPackage(XposedTweakbox.class, "handleLoadPackage", Callback.PRIORITY_DEFAULT);
+ XposedBridge.hookInitPackageResources(XposedTweakbox.class, "handleInitPackageResources", Callback.PRIORITY_DEFAULT);
+
+ if (pref.getBoolean("volume_keys_skip_track", false))
+ VolumeKeysSkipTrack.init(pref.getBoolean("volume_keys_skip_track_screenon", false));
+
+ }
+
+ @SuppressWarnings("unused")
+ private static void handleLoadPackage(String packageName, ClassLoader classLoader) {
+ if (packageName.equals("com.android.systemui")) {
+ SharedPreferences pref = AndroidAppHelper.getDefaultSharedPreferencesForPackage(MY_PACKAGE_NAME);
+ if (!pref.getBoolean("battery_full_notification", true)) {
+ try {
+ Class> classPowerUI = Class.forName("com.android.systemui.power.PowerUI", false, classLoader);
+ Method methodNotifyFullBatteryNotification = classPowerUI.getDeclaredMethod("notifyFullBatteryNotification");
+ XposedBridge.hookMethod(methodNotifyFullBatteryNotification, XposedTweakbox.class, "doNothing", Callback.PRIORITY_HIGHEST);
+ } catch (NoSuchMethodException ignored) {
+ } catch (Exception e) {
+ XposedBridge.log(e);
+ }
+ }
+
+ if (pref.getInt("statusbar_color", 0xdeadbeef) != 0xdeadbeef) {
+ // http://forum.xda-developers.com/showthread.php?t=1523703
+ try {
+ Constructor> constructLayoutParams = WindowManager.LayoutParams.class.getDeclaredConstructor(int.class, int.class, int.class, int.class, int.class);
+ XposedBridge.hookMethod(constructLayoutParams, XposedTweakbox.class, "handleInitLayoutParams", Callback.PRIORITY_HIGHEST);
+ } catch (Exception e) {
+ XposedBridge.log(e);
+ }
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static void handleInitPackageResources(String packageName, XResources res) {
+ if (packageName.equals("com.android.systemui")) {
+ SharedPreferences pref = AndroidAppHelper.getDefaultSharedPreferencesForPackage(MY_PACKAGE_NAME);
+
+ try {
+ res.setReplacement("com.android.systemui", "integer", "config_maxLevelOfSignalStrengthIndicator",
+ pref.getInt("num_signal_bars", 4));
+ } catch (Exception e) { XposedBridge.log(e); }
+
+ int statusbarColor = pref.getInt("statusbar_color", 0xdeadbeef);
+ if (statusbarColor != 0xdeadbeef) {
+ try {
+ res.setReplacement("com.android.systemui", "drawable", "status_bar_background", new ColorDrawable(statusbarColor));
+ } catch (Exception e) { XposedBridge.log(e); }
+ }
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static Object doNothing(Iterator iterator, Method method, Object thisObject, Object[] args) throws Throwable {
+ return null;
+ }
+
+ @SuppressWarnings("unused")
+ private static void handleInitLayoutParams(Iterator iterator, Constructor> method, Object thisObject, Object[] args) throws Throwable {
+ if ((Integer)args[4] == PixelFormat.RGB_565)
+ args[4] = PixelFormat.TRANSLUCENT;
+ XposedBridge.callNext(iterator, method, thisObject, args);
+ }
+}
diff --git a/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/XposedTweakboxSettings.java b/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/XposedTweakboxSettings.java
new file mode 100644
index 0000000..3177b2d
--- /dev/null
+++ b/XposedTweakbox/src/de/robv/android/xposed/mods/tweakbox/XposedTweakboxSettings.java
@@ -0,0 +1,26 @@
+package de.robv.android.xposed.mods.tweakbox;
+
+import android.app.Activity;
+import android.os.Bundle;
+import android.preference.PreferenceFragment;
+
+public class XposedTweakboxSettings extends Activity {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ setTitle(R.string.app_name);
+ super.onCreate(savedInstanceState);
+ setContentView(R.layout.settings);
+ }
+
+ public static class PrefsFragment extends PreferenceFragment {
+ @Override
+ public void onCreate(Bundle savedInstanceState) {
+ super.onCreate(savedInstanceState);
+
+ // this is important because although the handler classes that read these settings
+ // are in the same package, they are executed in the context of the hooked package
+ getPreferenceManager().setSharedPreferencesMode(MODE_WORLD_READABLE);
+ addPreferencesFromResource(R.xml.preferences);
+ }
+ }
+}
\ No newline at end of file