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