Full Code of Noisyfox/NoExclamation for AI

master 906b60213b2b cached
27 files
43.9 KB
11.4k tokens
75 symbols
1 requests
Download .txt
Repository: Noisyfox/NoExclamation
Branch: master
Commit: 906b60213b2b
Files: 27
Total size: 43.9 KB

Directory structure:
gitextract_wpgp_7p2/

├── .gitignore
├── README.md
├── app/
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── foxteam/
│           │           └── noisyfox/
│           │               └── noexclamation/
│           │                   ├── App.java
│           │                   ├── NewActivity.java
│           │                   ├── Utils.java
│           │                   └── adapter/
│           │                       ├── CommonConfigProvider.java
│           │                       ├── ConfigAdapterFactory.java
│           │                       ├── IConfigProvider.java
│           │                       ├── ITaskExecutor.java
│           │                       └── settings/
│           │                           ├── BaseSettingsItem.java
│           │                           ├── GlobalKeyedSettings.java
│           │                           ├── ISettingsItem.java
│           │                           ├── ListSettings.java
│           │                           ├── TextSettings.java
│           │                           └── ToggleSettings.java
│           └── res/
│               ├── values/
│               │   └── strings.xml
│               ├── values-en/
│               │   └── strings.xml
│               ├── values-zh/
│               │   └── strings.xml
│               └── xml/
│                   └── main_pref.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle

================================================
FILE CONTENTS
================================================

================================================
FILE: .gitignore
================================================

.gradle/
.idea/
*.iml
build
import-summary.txt
local.properties
*.apk


================================================
FILE: README.md
================================================
# NoExclamation
叹号杀手-去除安卓手机在国内时网络图标上的感叹号

https://www.noisyfox.cn/android-captive-portal.html


================================================
FILE: app/build.gradle
================================================
apply plugin: 'com.android.application'

android {
    compileSdkVersion 28

    defaultConfig {
        applicationId "org.foxteam.noisyfox.noexclamation"
        minSdkVersion 21
        targetSdkVersion 28
        resConfigs "zh", "en"
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
        }
    }
}


================================================
FILE: app/src/main/AndroidManifest.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
          package="org.foxteam.noisyfox.noexclamation"
          android:versionCode="8"
          android:versionName="@string/app_version_name">

    <application
        android:label="@string/app_name"
        android:name="App"
        android:icon="@drawable/ic_launcher"
        android:theme="@android:style/Theme.Material.Light.DarkActionBar"
        android:allowBackup="true">
        <activity
            android:name=".NewActivity"
            android:label="@string/app_name"
            android:configChanges="orientation|screenSize">
            <intent-filter>
                <action android:name="android.intent.action.MAIN"/>
                <category android:name="android.intent.category.LAUNCHER"/>
            </intent-filter>
        </activity>
    </application>
</manifest>


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/App.java
================================================
package org.foxteam.noisyfox.noexclamation;

import android.app.Application;

//This class allows global method for StringRes for translation

public class App extends Application {

    private static App app; //ApplicationContext reference (safe, no context leak)

    @Override
    public void onCreate() {
        super.onCreate();
        app = this;
    }

    public static String getStr(int resId) {
        return app.getString(resId);
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/NewActivity.java
================================================
package org.foxteam.noisyfox.noexclamation;

import android.app.AlertDialog;
import android.app.ProgressDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceCategory;
import android.widget.Toast;

import org.foxteam.noisyfox.noexclamation.adapter.ConfigAdapterFactory;
import org.foxteam.noisyfox.noexclamation.adapter.IConfigProvider;
import org.foxteam.noisyfox.noexclamation.adapter.ITaskExecutor;

import java.util.concurrent.locks.ReentrantLock;

import static org.foxteam.noisyfox.noexclamation.App.getStr;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public class NewActivity extends PreferenceActivity implements ITaskExecutor {

    private IConfigProvider provider;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.main_pref);

        PreferenceCategory category = (PreferenceCategory) findPreference("cat_detail_settings");

        provider = ConfigAdapterFactory.createProvider(this, this);
        provider.buildSettingsSection(category);

        findPreference("refresh").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                provider.refreshStatus();
                return true;
            }
        });
        findPreference("set_noisyfox").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                askForConfirm(getStr(R.string.setting_toNoisyFox), new Runnable() {
                    @Override
                    public void run() {
                        provider.setToNoisyfox();
                    }
                });
                return true;
            }
        });
        findPreference("set_google").setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                askForConfirm(getStr(R.string.setting_toGoogle), new Runnable() {
                    @Override
                    public void run() {
                        provider.resetToGoogle();
                    }
                });
                return true;
            }
        });

        runTask(getString(R.string.runTask_getRoot), new TaskRunnable() {
            @Override
            public Bundle run() {
                String result = Utils.cmdExecSu("id");
                if (result == null || !result.contains("uid=0")) {
                    return new Bundle();
                }
                return null;
            }
        }, new AfterTaskRunnable() {
            @Override
            public void run(Bundle result) {
                if (result != null) {
                    Toast.makeText(NewActivity.this, getStr(R.string.toast_needsRootMsg), Toast.LENGTH_LONG).show();
                }
                provider.refreshStatus();
            }
        });
    }

    private final ReentrantLock mSyncRoot = new ReentrantLock();
    private int mTaskCount = 0;
    private ProgressDialog mTaskDialog = null;

    public void runTask(String msg, final TaskRunnable task, final AfterTaskRunnable after) {
        mSyncRoot.lock();
        try {
            mTaskCount++;
            if (mTaskDialog == null) {
                mTaskDialog = new ProgressDialog(this);
                mTaskDialog.setCancelable(false);
                mTaskDialog.setIndeterminate(true);
            }
            mTaskDialog.setMessage(msg);
            mTaskDialog.show();
        } finally {
            mSyncRoot.unlock();
        }

        Thread t = new Thread() {
            @Override
            public void run() {
                Bundle result = null;
                try {
                    result = task.run();
                } finally {
                    final Bundle b = result;
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            after.run(b);
                            mSyncRoot.lock();
                            try {
                                mTaskCount--;
                                if (mTaskCount == 0) {
                                    mTaskDialog.dismiss();
                                }
                            } finally {
                                mSyncRoot.unlock();
                            }
                        }
                    });
                }
            }
        };
        t.start();
    }

    private void askForConfirm(String msg, final Runnable doStuff) {
        AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage(msg);
        builder.setPositiveButton(getStr(R.string.dialogBtn_Confirm), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                doStuff.run();
            }
        });
        builder.setNegativeButton(getStr(R.string.dialogBtn_Cancel), new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
            }
        });
        builder.show();
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/Utils.java
================================================
package org.foxteam.noisyfox.noexclamation;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public class Utils {

    public static String cmdExecSu(String cmd) {
        Process p = null;
        BufferedReader reader = null;
        BufferedWriter writer = null;
        try {
            p = new ProcessBuilder("su").start();
            writer = new BufferedWriter(new OutputStreamWriter(p.getOutputStream()));
            InputStream is = p.getInputStream();
            reader = new BufferedReader(new InputStreamReader(is));
            writer.write(cmd);
            writer.write("\n");
            writer.write("exit\n");
            writer.flush();
            StringBuilder sb = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                sb.append(line);
            }
            p.waitFor();
            return sb.toString();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (writer != null) {
                try {
                    writer.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (p != null) {
                p.destroy();
            }
        }
        return null;
    }

}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/CommonConfigProvider.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter;

import android.content.Context;
import android.os.Bundle;
import android.preference.PreferenceCategory;

import org.foxteam.noisyfox.noexclamation.R;
import org.foxteam.noisyfox.noexclamation.adapter.settings.ISettingsItem;

import java.util.ArrayList;
import java.util.List;

import static org.foxteam.noisyfox.noexclamation.App.getStr;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public class CommonConfigProvider implements IConfigProvider, ISettingsItem.OnSettingsChangedListener {

    private final List<ISettingsItem> mAllSettings = new ArrayList<>();
    private final Context mContext;
    private final ITaskExecutor mTaskExecutor;

    public CommonConfigProvider(Context context,
                                ITaskExecutor taskExecutor) {
        mContext = context;
        mTaskExecutor = taskExecutor;
    }

    public void addSettings(ISettingsItem settingsItem) {
        settingsItem.injectTaskExecutor(mTaskExecutor);
        settingsItem.setOnSettingsChangedListener(this);
        mAllSettings.add(settingsItem);
    }

    @Override
    public void buildSettingsSection(PreferenceCategory category) {
        for (ISettingsItem s : mAllSettings) {
            category.addPreference(s.onCreatePreference(mContext));
        }
    }

    @Override
    public void refreshStatus() {
        mTaskExecutor.runTask(getStr(R.string.status_refresh), new ITaskExecutor.TaskRunnable() {
            @Override
            public Bundle run() {
                Bundle result = new Bundle();
                for (ISettingsItem s : mAllSettings) {
                    s.reloadValue(result);
                }
                return result;
            }
        }, new ITaskExecutor.AfterTaskRunnable() {
            @Override
            public void run(Bundle result) {
                for (ISettingsItem s : mAllSettings) {
                    s.refreshPreference(result);
                }
            }
        });
    }

    @Override
    public void resetToGoogle() {
        mTaskExecutor.runTask(getStr(R.string.status_reset), new ITaskExecutor.TaskRunnable() {
            @Override
            public Bundle run() {
                for (ISettingsItem s : mAllSettings) {
                    s.resetToGoogle();
                }
                return null;
            }
        }, new ITaskExecutor.AfterTaskRunnable() {
            @Override
            public void run(Bundle result) {
                refreshStatus();
            }
        });
    }

    @Override
    public void setToNoisyfox() {
        mTaskExecutor.runTask(getStr(R.string.status_setNoisyFox), new ITaskExecutor.TaskRunnable() {
            @Override
            public Bundle run() {
                for (ISettingsItem s : mAllSettings) {
                    s.setToNoisyfox();
                }
                return null;
            }
        }, new ITaskExecutor.AfterTaskRunnable() {
            @Override
            public void run(Bundle result) {
                refreshStatus();
            }
        });
    }

    @Override
    public void onSettingsChanged(ISettingsItem settingsItem) {
        refreshStatus();
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/ConfigAdapterFactory.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter;

import android.content.Context;
import android.provider.Settings;

import org.foxteam.noisyfox.noexclamation.R;
import org.foxteam.noisyfox.noexclamation.adapter.settings.ListSettings;
import org.foxteam.noisyfox.noexclamation.adapter.settings.TextSettings;
import org.foxteam.noisyfox.noexclamation.adapter.settings.ToggleSettings;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;

import static org.foxteam.noisyfox.noexclamation.App.getStr;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public class ConfigAdapterFactory {
    public static IConfigProvider createProvider(Context context,
                                                 ITaskExecutor taskExecutor) {
        CommonConfigProvider provider = new CommonConfigProvider(context, taskExecutor);

        // Check for android 7.1.2 which use 'captive_portal_mode' instead of 'captive_portal_detection_enabled'
        if (isSettingsPresent("captive_portal_mode")) {
            provider.addSettings(new ListSettings(getStr(R.string.portalModeTitle),
                    "captive_portal_mode",
                    new String[]{"0", "1", "2"},
                    new String[]{getStr(R.string.portalMode_disable), getStr(R.string.portalMode_promptOnly), getStr(R.string.portalMode_ignoreLoginPrompts)},
                    "1"));
        } else {
            provider.addSettings(new ToggleSettings(getStr(R.string.portalDetectionTitle),
                    "captive_portal_detection_enabled", "1", "0", ToggleSettings.State.Positive, "On", "Off", getStr(R.string.progress_open), getStr(R.string.progress_close)));
        }

        // For android 7.0+
        if (isSettingsPresent("captive_portal_use_https")) {
            provider.addSettings(new ToggleSettings(getStr(R.string.setting_useHttps),
                    "captive_portal_use_https", "1", "0", ToggleSettings.State.Positive, "On", "Off", getStr(R.string.progress_open), getStr(R.string.progress_close)));
        }

        boolean a711 = false;
        if (isSettingsPresent("captive_portal_http_url")) {
            a711 = true;
            provider.addSettings(new TextSettings(getStr(R.string.protocol_http), "captive_portal_http_url", "http://www.noisyfox.io/generate_204"));
        }
        if (isSettingsPresent("captive_portal_https_url")) {
            a711 = true;
            provider.addSettings(new TextSettings(getStr(R.string.protocol_https), "captive_portal_https_url", "https://www.noisyfox.io/generate_204"));
        }
        if (!a711) {
            provider.addSettings(new TextSettings(getStr(R.string.protocol_default), "captive_portal_server", "noisyfox.io"));
        }

        return provider;
    }

    private static boolean isSettingsPresent(String key) {
        Class clazz = Settings.Global.class;

        for (Field field : clazz.getDeclaredFields()) {
            if (field.getType().equals(String.class) && Modifier.isStatic(field.getModifiers())) {
                try {
                    String v = (String) field.get(null);
                    if (key.equals(v)) {
                        return true;
                    }
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
        return false;
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/IConfigProvider.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter;

import android.preference.PreferenceCategory;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public interface IConfigProvider {

    void buildSettingsSection(PreferenceCategory category);

    void refreshStatus();

    void resetToGoogle();

    void setToNoisyfox();
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/ITaskExecutor.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter;

import android.os.Bundle;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public interface ITaskExecutor {
    void runTask(String msg, TaskRunnable task, AfterTaskRunnable after);

    interface AfterTaskRunnable {
        void run(Bundle result);
    }

    interface TaskRunnable {
        Bundle run();
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/BaseSettingsItem.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter.settings;

import org.foxteam.noisyfox.noexclamation.adapter.ITaskExecutor;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public abstract class BaseSettingsItem implements ISettingsItem {
    private OnSettingsChangedListener listener;
    protected ITaskExecutor executor;

    @Override
    public void setOnSettingsChangedListener(OnSettingsChangedListener listener) {
        this.listener = listener;
    }

    @Override
    public void setToNoisyfox() {
    }

    @Override
    public void resetToGoogle() {
    }

    @Override
    public void injectTaskExecutor(ITaskExecutor executor) {
        this.executor = executor;
    }

    protected void notifySettingsChanged() {
        if (listener != null) {
            listener.onSettingsChanged(this);
        }
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/GlobalKeyedSettings.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter.settings;

import android.os.Bundle;

import org.foxteam.noisyfox.noexclamation.Utils;
import org.foxteam.noisyfox.noexclamation.adapter.ITaskExecutor;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public abstract class GlobalKeyedSettings extends BaseSettingsItem {
    protected final String mKey;

    protected GlobalKeyedSettings(String key) {
        mKey = key;
    }

    @Override
    public void reloadValue(Bundle valueOut) {
        valueOut.putString(mKey, Utils.cmdExecSu("settings get global " + mKey));
    }

    protected String getValue(Bundle value) {
        String v = null;
        if (value != null) {
            v = value.getString(mKey);
        }

        return v;
    }

    protected void setValue(String value) {
        Utils.cmdExecSu(String.format("settings put global %s %s", mKey, value));
    }

    protected void removeValue() {
        Utils.cmdExecSu("settings delete global " + mKey);
    }

    protected void setValueAsync(String msg, final String value) {
        executor.runTask(msg, new ITaskExecutor.TaskRunnable() {
            @Override
            public Bundle run() {
                setValue(value);
                return null;
            }
        }, new ITaskExecutor.AfterTaskRunnable() {
            @Override
            public void run(Bundle result) {
                notifySettingsChanged();
            }
        });
    }

    protected void removeValueAsync(String msg) {
        executor.runTask(msg, new ITaskExecutor.TaskRunnable() {
            @Override
            public Bundle run() {
                removeValue();
                return null;
            }
        }, new ITaskExecutor.AfterTaskRunnable() {
            @Override
            public void run(Bundle result) {
                notifySettingsChanged();
            }
        });
    }

}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ISettingsItem.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter.settings;

import android.content.Context;
import android.os.Bundle;
import android.preference.Preference;

import org.foxteam.noisyfox.noexclamation.adapter.ITaskExecutor;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public interface ISettingsItem {
    Preference onCreatePreference(Context context);

    void reloadValue(Bundle valueOut);

    void refreshPreference(Bundle value);

    void setToNoisyfox();

    void resetToGoogle();

    void setOnSettingsChangedListener(OnSettingsChangedListener listener);

    void injectTaskExecutor(ITaskExecutor executor);

    interface OnSettingsChangedListener {
        void onSettingsChanged(ISettingsItem settingsItem);
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ListSettings.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter.settings;

import android.content.Context;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;

import org.foxteam.noisyfox.noexclamation.R;

import static org.foxteam.noisyfox.noexclamation.App.getStr;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public class ListSettings extends GlobalKeyedSettings implements Preference.OnPreferenceChangeListener {
    private ListPreference mPreference;
    private final String mTitle;
    private final String[] mValues;
    private final String[] mDisplayValues;
    private final int defaultValueIndex;

    public ListSettings(String title, String key, String values[], String displayValues[], String defaultValue) {
        super(key);
        mTitle = title;
        mValues = values;
        mDisplayValues = displayValues;

        int d = -1;
        for (int i = 0; i < values.length; i++) {
            if (defaultValue.equals(values[i])) {
                d = i;
                break;
            }
        }
        if (d == -1) {
            throw new RuntimeException("default value not in valid values!");
        }
        defaultValueIndex = d;
    }

    @Override
    public Preference onCreatePreference(Context context) {
        mPreference = new ListPreference(context);
        mPreference.setEntryValues(mValues);
        mPreference.setEntries(mDisplayValues);
        mPreference.setTitle(mTitle);

        refreshPreference(null);

        return mPreference;
    }

    @Override
    public void refreshPreference(Bundle value) {
        mPreference.setOnPreferenceChangeListener(null);

        String v = getValue(value);
        if (v == null || "null".equals(v)) {
            mPreference.setValueIndex(defaultValueIndex);
            mPreference.setSummary(v == null ? getStr(R.string.status_unknown) : mDisplayValues[defaultValueIndex]);
        } else {
            mPreference.setValue(v);
            mPreference.setSummary(mPreference.getEntry());
        }

        mPreference.setOnPreferenceChangeListener(this);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        setValueAsync("设置中", (String) newValue);
        return false;
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/TextSettings.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter.settings;

import android.content.Context;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.Preference;

import org.foxteam.noisyfox.noexclamation.R;

import static org.foxteam.noisyfox.noexclamation.App.getStr;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public class TextSettings extends GlobalKeyedSettings implements Preference.OnPreferenceChangeListener {
    private EditTextPreference mPreference;
    private final String mTitle;
    private final String mDefaultValue;

    public TextSettings(String title, String key, String defaultValue) {
        super(key);
        mTitle = title;
        mDefaultValue = defaultValue;
    }

    public String getDefaultValue() {
        return mDefaultValue;
    }

    @Override
    public Preference onCreatePreference(Context context) {
        mPreference = new EditTextPreference(context);
        mPreference.setTitle(mTitle);
        mPreference.setDialogTitle(mTitle);

        refreshPreference(null);

        return mPreference;
    }

    @Override
    public void refreshPreference(Bundle value) {
        mPreference.setOnPreferenceChangeListener(null);

        String v = getValue(value);
        if (v == null || "null".equals(v)) {
            mPreference.setSummary(getStr(R.string.value_isDefault));
            mPreference.setText(mDefaultValue);
        } else {
            mPreference.setSummary(v);
            mPreference.setText(v);
        }

        mPreference.setOnPreferenceChangeListener(this);
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        setValueAsync("设置中", (String) newValue);
        return false;
    }

    @Override
    public void setToNoisyfox() {
        setValue(getDefaultValue());
    }

    @Override
    public void resetToGoogle() {
        removeValue();
    }
}


================================================
FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ToggleSettings.java
================================================
package org.foxteam.noisyfox.noexclamation.adapter.settings;

import android.content.Context;
import android.os.Bundle;
import android.preference.Preference;
import android.preference.SwitchPreference;

import org.foxteam.noisyfox.noexclamation.R;

import static org.foxteam.noisyfox.noexclamation.App.getStr;

/**
 * Created by Noisyfox on 2017/7/1.
 */

public class ToggleSettings extends GlobalKeyedSettings implements Preference.OnPreferenceChangeListener {

    private SwitchPreference mPreference;
    private final String mTitle;
    private final String mPositiveValue;
    private final String mNegativeValue;
    private final State mStateIfNotSet;
    private final String mPositiveSummary;
    private final String mNegativeSummary;
    private final String mPositiveProgress;
    private final String mNegativeProgress;

    public ToggleSettings(String title, String key, String valuePositive, String valueNegative, State stateIfNotSet,
                          String summaryPositive, String summaryNegative,
                          String progressPositive, String progressNegative) {
        super(key);
        mTitle = title;
        mPositiveValue = valuePositive;
        mNegativeValue = valueNegative;
        mStateIfNotSet = stateIfNotSet;
        mPositiveSummary = summaryPositive;
        mNegativeSummary = summaryNegative;
        mPositiveProgress = progressPositive;
        mNegativeProgress = progressNegative;
    }

    @Override
    public Preference onCreatePreference(Context context) {
        mPreference = new SwitchPreference(context);

        mPreference.setTitle(mTitle);

        refreshPreference(null);

        return mPreference;
    }

    public State getState(String currentValue) {
        if (currentValue != null) {
            if (currentValue.equals("null")) {
                return mStateIfNotSet;
            } else if (currentValue.equals(mNegativeValue)) {
                return State.Negative;
            } else if (currentValue.equals(mPositiveValue)) {
                return State.Positive;
            }
        }
        return State.Unknown;
    }

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        boolean checked = (boolean) newValue;
        setValueAsync(checked ? mPositiveProgress : mNegativeProgress, checked ? mPositiveValue : mNegativeValue);
        return false;
    }

    public enum State {
        Positive, Negative, Unknown
    }

    @Override
    public void refreshPreference(Bundle value) {
        mPreference.setOnPreferenceChangeListener(null);
        String v = getValue(value);

        State s = getState(v);
        switch (s) {
            case Positive:
                mPreference.setSummary(mPositiveSummary);
                mPreference.setChecked(true);
                break;
            case Negative:
                mPreference.setSummary(mNegativeSummary);
                mPreference.setChecked(false);
                break;
            case Unknown:
                mPreference.setSummary(getStr(R.string.status_unknown));
                mPreference.setChecked(false);
                break;
        }
        mPreference.setOnPreferenceChangeListener(this);
    }
}


================================================
FILE: app/src/main/res/values/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">叹号杀手</string>
    <string name="app_version_name" translatable="false">3.0</string>

    <string name="setting_toNoisyFox">即将把服务器地址设置为 noisyfox.io,是否继续?</string>
    <string name="setting_toGoogle">即将把服务器地址重置为默认值,是否继续?</string>
    <string name="runTask_getRoot">获取root权限</string>

    <string name="toast_needsRootMsg">无法获得root权限!程序将可能无法正常使用!</string>
    <string name="dialogBtn_Confirm">继续</string>
    <string name="dialogBtn_Cancel">取消</string>

    <string name="portalModeTitle">Captive Portal 检测模式</string>
    <string name="portalMode_disable">完全禁用检测</string>
    <string name="portalMode_promptOnly">检测到需要登录则弹框提醒</string>
    <string name="portalMode_ignoreLoginPrompts">检测到需要登录则自动断开此网络并不再自动连接</string>

    <string name="portalDetectionTitle">Captive Portal 检测</string>
    <string name="progress_open">开启中</string>
    <string name="progress_close">关闭中</string>

    <string name="protocol_http">服务地址(http)</string>
    <string name="protocol_https">服务地址(https)</string>
    <string name="protocol_default">服务地址</string>

    <string name="status_refresh">刷新当前状态</string>
    <string name="status_reset">重置为默认值</string>
    <string name="status_setNoisyFox">设置为 noisyfox.io</string>

    <string name="version_prefix">版本</string>

    <string name="prefSummary_visitBlog">欢迎访问我的博客来支持我的作品! 猛戳这里 一noisyfox.io</string>
    <string name="prefTitle_visitBlog">求关注!求打赏!</string>
    <string name="prefCategory_about">关于</string>

    <string name="prefSummary_visitGithub">猛戳这里 一github.com/Noisyfox/NoExclamation</string>
    <string name="prefTitle_openSrcGithub">开源啦!</string>
    <string name="prefCategory_detailedSettings">详细设置</string>

    <string name="prefTitle_resetToDefault">重置为默认值</string>
    <string name="prefSummary_resetToDefault">将 portal server 重置为系统默认设置。</string>
    <string name="prefTitle_setToNoisyfox">设为 noisyfox.io</string>
    <string name="prefSummary_setToNoisyfox">将 portal server 设置为 noisyfox.io。</string>

    <string name="prefCategory_portalSetup">Portal Server 一键设置</string>
    <string name="prefTitle_refreshStatus">刷新当前状态</string>

    <string name="prefCategory_Instructions">使用说明</string>
    <string name="prefSummary_Instructions">最简单的去掉网络连接的感叹号的方式: 戳 设为 noisyfox.io 选项,然后开飞行模式,然后再关飞行模式,搞定!</string>
    <string name="status_unknown">未知</string>
    <string name="value_isDefault">默认</string>
    <string name="setting_useHttps">启用 https</string>
</resources>


================================================
FILE: app/src/main/res/values-en/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <!--
    English Translation
    by Bryan Walsh
    (https://github.com/bwalsh0)
    -->

    <string name="app_name">NoExclamation</string>

    <string name="setting_toGoogle">Reset to system default?</string>
    <string name="runTask_getRoot">Grant root permission</string>

    <string name="toast_needsRootMsg">Unable to access root priveliges! This application may not work as intended.</string>
    <string name="dialogBtn_Confirm">Confirm</string>
    <string name="dialogBtn_Cancel">Cancel</string>

    <string name="portalModeTitle">Captive Portal Detection Mode</string>
    <string name="portalMode_disable">Disable</string>
    <string name="portalMode_promptOnly">Prompt for login</string>

    <string name="portalDetectionTitle">Captive Portal Detection</string>
    <string name="progress_open">Opening</string>
    <string name="progress_close">Closing</string>

    <string name="protocol_http">HTTP URL</string>
    <string name="protocol_https">HTTPS URL</string>
    <string name="protocol_default">Default Protocol</string>

    <string name="status_refresh">Refreshing status</string>
    <string name="status_reset">Resetting to default</string>
    <string name="status_setNoisyFox">Set to noisyfox.io</string>

    <string name="version_prefix">Version</string>

    <string name="prefSummary_visitBlog">Visit my blog to support my work! Visit 一noisyfox.io</string>
    <string name="prefTitle_visitBlog">Check out the blog!</string>
    <string name="prefCategory_about">About</string>

    <string name="prefSummary_visitGithub">Visit 一github.com/Noisyfox/NoExclamation</string>
    <string name="prefTitle_openSrcGithub">Open Source!</string>
    <string name="prefCategory_detailedSettings">Advanced Settings</string>

    <string name="prefTitle_resetToDefault">Reset to default</string>
    <string name="prefSummary_resetToDefault">Reset portal server to system default</string>
    <string name="prefTitle_setToNoisyfox">Set to noisyfox.io</string>
    <string name="prefSummary_setToNoisyfox">Set portal server to noisyfox.io</string>

    <string name="prefCategory_portalSetup">One-Click Setup</string>
    <string name="prefTitle_refreshStatus">Refresh Status</string>

    <string name="prefCategory_Instructions">Instructions</string>
    <string name="prefSummary_Instructions">This is the easiest way to get rid of the exclamation mark (error mode) of a Wi-Fi connection. Tap \"Set to noisyfox.io\", turn on Airplane mode, turn it back off, and it will be fixed!</string>
    <string name="portalMode_ignoreLoginPrompts">Ignore networks with login prompts</string>
    <string name="setting_toNoisyFox">Set server to noisyfox.io?</string>
    <string name="status_unknown">Unknown</string>
    <string name="setting_useHttps">Use HTTPS</string>
    <string name="value_isDefault">Default</string>
</resources>


================================================
FILE: app/src/main/res/values-zh/strings.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<resources>
    <string name="app_name">叹号杀手</string>

    <string name="setting_toNoisyFox">即将把服务器地址设置为 noisyfox.io,是否继续?</string>
    <string name="setting_toGoogle">即将把服务器地址重置为默认值,是否继续?</string>
    <string name="runTask_getRoot">获取root权限</string>

    <string name="toast_needsRootMsg">无法获得root权限!程序将可能无法正常使用!</string>
    <string name="dialogBtn_Confirm">继续</string>
    <string name="dialogBtn_Cancel">取消</string>

    <string name="portalModeTitle">Captive Portal 检测模式</string>
    <string name="portalMode_disable">完全禁用检测</string>
    <string name="portalMode_promptOnly">检测到需要登录则弹框提醒</string>
    <string name="portalMode_ignoreLoginPrompts">检测到需要登录则自动断开此网络并不再自动连接</string>

    <string name="portalDetectionTitle">Captive Portal 检测</string>
    <string name="progress_open">开启中</string>
    <string name="progress_close">关闭中</string>

    <string name="protocol_http">服务地址(http)</string>
    <string name="protocol_https">服务地址(https)</string>
    <string name="protocol_default">服务地址</string>

    <string name="status_refresh">刷新当前状态</string>
    <string name="status_reset">重置为默认值</string>
    <string name="status_setNoisyFox">设置为 noisyfox.io</string>

    <string name="version_prefix">版本</string>

    <string name="prefSummary_visitBlog">欢迎访问我的博客来支持我的作品! 猛戳这里 一noisyfox.io</string>
    <string name="prefTitle_visitBlog">求关注!求打赏!</string>
    <string name="prefCategory_about">关于</string>

    <string name="prefSummary_visitGithub">猛戳这里 一github.com/Noisyfox/NoExclamation</string>
    <string name="prefTitle_openSrcGithub">开源啦!</string>
    <string name="prefCategory_detailedSettings">详细设置</string>

    <string name="prefTitle_resetToDefault">重置为默认值</string>
    <string name="prefSummary_resetToDefault">将 portal server 重置为系统默认设置。</string>
    <string name="prefTitle_setToNoisyfox">设为 noisyfox.io</string>
    <string name="prefSummary_setToNoisyfox">将 portal server 设置为 noisyfox.io。</string>

    <string name="prefCategory_portalSetup">Portal Server 一键设置</string>
    <string name="prefTitle_refreshStatus">刷新当前状态</string>

    <string name="prefCategory_Instructions">使用说明</string>
    <string name="prefSummary_Instructions">最简单的去掉网络连接的感叹号的方式: 戳 设为 noisyfox.io 选项,然后开飞行模式,然后再关飞行模式,搞定!</string>
    <string name="status_unknown">未知</string>
    <string name="setting_useHttps">启用 https</string>
    <string name="value_isDefault">默认</string>
</resources>


================================================
FILE: app/src/main/res/xml/main_pref.xml
================================================
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <PreferenceCategory android:title="@string/prefCategory_Instructions">
        <Preference android:summary="@string/prefSummary_Instructions" />
    </PreferenceCategory>

    <Preference
        android:key="refresh"
        android:title="@string/prefTitle_refreshStatus" />

    <PreferenceCategory android:title="@string/prefCategory_portalSetup">
        <Preference
            android:key="set_noisyfox"
            android:summary="@string/prefSummary_setToNoisyfox"
            android:title="@string/prefTitle_setToNoisyfox" />
        <Preference
            android:key="set_google"
            android:summary="@string/prefSummary_resetToDefault"
            android:title="@string/prefTitle_resetToDefault" />
    </PreferenceCategory>

    <PreferenceCategory
        android:key="cat_detail_settings"
        android:title="@string/prefCategory_detailedSettings">

    </PreferenceCategory>

    <PreferenceCategory android:title="@string/prefCategory_about">
        <Preference
            android:summary="@string/prefSummary_visitGithub"
            android:title="@string/prefTitle_openSrcGithub">
            <intent
                android:action="android.intent.action.VIEW"
                android:data="https://github.com/Noisyfox/NoExclamation" />
        </Preference>
        <Preference
            android:summary="@string/prefSummary_visitBlog"
            android:title="@string/prefTitle_visitBlog">
            <intent
                android:action="android.intent.action.VIEW"
                android:data="https://www.noisyfox.io" />
        </Preference>
        <Preference
            android:summary="@string/app_version_name"
            android:title="@string/version_prefix" />
    </PreferenceCategory>
</PreferenceScreen>

================================================
FILE: build.gradle
================================================
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
    repositories {
        jcenter()
        google()
    }
    dependencies {
        classpath 'com.android.tools.build:gradle:3.3.2'
    }
}

allprojects {
    repositories {
        jcenter()
        google()
    }
}


================================================
FILE: gradle/wrapper/gradle-wrapper.properties
================================================
#Mon Mar 18 10:14:12 AEDT 2019
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip


================================================
FILE: gradlew
================================================
#!/usr/bin/env bash

##############################################################################
##
##  Gradle start up script for UN*X
##
##############################################################################

# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""

APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`

# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"

warn ( ) {
    echo "$*"
}

die ( ) {
    echo
    echo "$*"
    echo
    exit 1
}

# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
  CYGWIN* )
    cygwin=true
    ;;
  Darwin* )
    darwin=true
    ;;
  MINGW* )
    msys=true
    ;;
esac

# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
    ls=`ls -ld "$PRG"`
    link=`expr "$ls" : '.*-> \(.*\)$'`
    if expr "$link" : '/.*' > /dev/null; then
        PRG="$link"
    else
        PRG=`dirname "$PRG"`"/$link"
    fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null

CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar

# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
        # IBM's JDK on AIX uses strange locations for the executables
        JAVACMD="$JAVA_HOME/jre/sh/java"
    else
        JAVACMD="$JAVA_HOME/bin/java"
    fi
    if [ ! -x "$JAVACMD" ] ; then
        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
    fi
else
    JAVACMD="java"
    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.

Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi

# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
    MAX_FD_LIMIT=`ulimit -H -n`
    if [ $? -eq 0 ] ; then
        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
            MAX_FD="$MAX_FD_LIMIT"
        fi
        ulimit -n $MAX_FD
        if [ $? -ne 0 ] ; then
            warn "Could not set maximum file descriptor limit: $MAX_FD"
        fi
    else
        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
    fi
fi

# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi

# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
    JAVACMD=`cygpath --unix "$JAVACMD"`

    # We build the pattern for arguments to be converted via cygpath
    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
    SEP=""
    for dir in $ROOTDIRSRAW ; do
        ROOTDIRS="$ROOTDIRS$SEP$dir"
        SEP="|"
    done
    OURCYGPATTERN="(^($ROOTDIRS))"
    # Add a user-defined pattern to the cygpath arguments
    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
    fi
    # Now convert the arguments - kludge to limit ourselves to /bin/sh
    i=0
    for arg in "$@" ; do
        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option

        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
        else
            eval `echo args$i`="\"$arg\""
        fi
        i=$((i+1))
    done
    case $i in
        (0) set -- ;;
        (1) set -- "$args0" ;;
        (2) set -- "$args0" "$args1" ;;
        (3) set -- "$args0" "$args1" "$args2" ;;
        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
    esac
fi

# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
    JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"

exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"


================================================
FILE: gradlew.bat
================================================
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem  Gradle startup script for Windows
@rem
@rem ##########################################################################

@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal

@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=

set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%

@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome

set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init

echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe

if exist "%JAVA_EXE%" goto init

echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.

goto fail

:init
@rem Get command-line arguments, handling Windowz variants

if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args

:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2

:win9xME_args_slurp
if "x%~1" == "x" goto execute

set CMD_LINE_ARGS=%*
goto execute

:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$

:execute
@rem Setup the command line

set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar

@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%

:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd

:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1

:mainEnd
if "%OS%"=="Windows_NT" endlocal

:omega


================================================
FILE: settings.gradle
================================================
include ':app'
Download .txt
gitextract_wpgp_7p2/

├── .gitignore
├── README.md
├── app/
│   ├── build.gradle
│   └── src/
│       └── main/
│           ├── AndroidManifest.xml
│           ├── java/
│           │   └── org/
│           │       └── foxteam/
│           │           └── noisyfox/
│           │               └── noexclamation/
│           │                   ├── App.java
│           │                   ├── NewActivity.java
│           │                   ├── Utils.java
│           │                   └── adapter/
│           │                       ├── CommonConfigProvider.java
│           │                       ├── ConfigAdapterFactory.java
│           │                       ├── IConfigProvider.java
│           │                       ├── ITaskExecutor.java
│           │                       └── settings/
│           │                           ├── BaseSettingsItem.java
│           │                           ├── GlobalKeyedSettings.java
│           │                           ├── ISettingsItem.java
│           │                           ├── ListSettings.java
│           │                           ├── TextSettings.java
│           │                           └── ToggleSettings.java
│           └── res/
│               ├── values/
│               │   └── strings.xml
│               ├── values-en/
│               │   └── strings.xml
│               ├── values-zh/
│               │   └── strings.xml
│               └── xml/
│                   └── main_pref.xml
├── build.gradle
├── gradle/
│   └── wrapper/
│       ├── gradle-wrapper.jar
│       └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
Download .txt
SYMBOL INDEX (75 symbols across 13 files)

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/App.java
  class App (line 7) | public class App extends Application {
    method onCreate (line 11) | @Override
    method getStr (line 17) | public static String getStr(int resId) {

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/NewActivity.java
  class NewActivity (line 24) | public class NewActivity extends PreferenceActivity implements ITaskExec...
    method onCreate (line 28) | @Override
    method runTask (line 94) | public void runTask(String msg, final TaskRunnable task, final AfterTa...
    method askForConfirm (line 138) | private void askForConfirm(String msg, final Runnable doStuff) {

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/Utils.java
  class Utils (line 14) | public class Utils {
    method cmdExecSu (line 16) | public static String cmdExecSu(String cmd) {

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/CommonConfigProvider.java
  class CommonConfigProvider (line 19) | public class CommonConfigProvider implements IConfigProvider, ISettingsI...
    method CommonConfigProvider (line 25) | public CommonConfigProvider(Context context,
    method addSettings (line 31) | public void addSettings(ISettingsItem settingsItem) {
    method buildSettingsSection (line 37) | @Override
    method refreshStatus (line 44) | @Override
    method resetToGoogle (line 65) | @Override
    method setToNoisyfox (line 83) | @Override
    method onSettingsChanged (line 101) | @Override

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/ConfigAdapterFactory.java
  class ConfigAdapterFactory (line 20) | public class ConfigAdapterFactory {
    method createProvider (line 21) | public static IConfigProvider createProvider(Context context,
    method isSettingsPresent (line 59) | private static boolean isSettingsPresent(String key) {

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/IConfigProvider.java
  type IConfigProvider (line 9) | public interface IConfigProvider {
    method buildSettingsSection (line 11) | void buildSettingsSection(PreferenceCategory category);
    method refreshStatus (line 13) | void refreshStatus();
    method resetToGoogle (line 15) | void resetToGoogle();
    method setToNoisyfox (line 17) | void setToNoisyfox();

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/ITaskExecutor.java
  type ITaskExecutor (line 9) | public interface ITaskExecutor {
    method runTask (line 10) | void runTask(String msg, TaskRunnable task, AfterTaskRunnable after);
    type AfterTaskRunnable (line 12) | interface AfterTaskRunnable {
      method run (line 13) | void run(Bundle result);
    type TaskRunnable (line 16) | interface TaskRunnable {
      method run (line 17) | Bundle run();

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/BaseSettingsItem.java
  class BaseSettingsItem (line 9) | public abstract class BaseSettingsItem implements ISettingsItem {
    method setOnSettingsChangedListener (line 13) | @Override
    method setToNoisyfox (line 18) | @Override
    method resetToGoogle (line 22) | @Override
    method injectTaskExecutor (line 26) | @Override
    method notifySettingsChanged (line 31) | protected void notifySettingsChanged() {

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/GlobalKeyedSettings.java
  class GlobalKeyedSettings (line 12) | public abstract class GlobalKeyedSettings extends BaseSettingsItem {
    method GlobalKeyedSettings (line 15) | protected GlobalKeyedSettings(String key) {
    method reloadValue (line 19) | @Override
    method getValue (line 24) | protected String getValue(Bundle value) {
    method setValue (line 33) | protected void setValue(String value) {
    method removeValue (line 37) | protected void removeValue() {
    method setValueAsync (line 41) | protected void setValueAsync(String msg, final String value) {
    method removeValueAsync (line 56) | protected void removeValueAsync(String msg) {

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ISettingsItem.java
  type ISettingsItem (line 13) | public interface ISettingsItem {
    method onCreatePreference (line 14) | Preference onCreatePreference(Context context);
    method reloadValue (line 16) | void reloadValue(Bundle valueOut);
    method refreshPreference (line 18) | void refreshPreference(Bundle value);
    method setToNoisyfox (line 20) | void setToNoisyfox();
    method resetToGoogle (line 22) | void resetToGoogle();
    method setOnSettingsChangedListener (line 24) | void setOnSettingsChangedListener(OnSettingsChangedListener listener);
    method injectTaskExecutor (line 26) | void injectTaskExecutor(ITaskExecutor executor);
    type OnSettingsChangedListener (line 28) | interface OnSettingsChangedListener {
      method onSettingsChanged (line 29) | void onSettingsChanged(ISettingsItem settingsItem);

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ListSettings.java
  class ListSettings (line 16) | public class ListSettings extends GlobalKeyedSettings implements Prefere...
    method ListSettings (line 23) | public ListSettings(String title, String key, String values[], String ...
    method onCreatePreference (line 42) | @Override
    method refreshPreference (line 54) | @Override
    method onPreferenceChange (line 70) | @Override

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/TextSettings.java
  class TextSettings (line 16) | public class TextSettings extends GlobalKeyedSettings implements Prefere...
    method TextSettings (line 21) | public TextSettings(String title, String key, String defaultValue) {
    method getDefaultValue (line 27) | public String getDefaultValue() {
    method onCreatePreference (line 31) | @Override
    method refreshPreference (line 42) | @Override
    method onPreferenceChange (line 58) | @Override
    method setToNoisyfox (line 64) | @Override
    method resetToGoogle (line 69) | @Override

FILE: app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ToggleSettings.java
  class ToggleSettings (line 16) | public class ToggleSettings extends GlobalKeyedSettings implements Prefe...
    method ToggleSettings (line 28) | public ToggleSettings(String title, String key, String valuePositive, ...
    method onCreatePreference (line 42) | @Override
    method getState (line 53) | public State getState(String currentValue) {
    method onPreferenceChange (line 66) | @Override
    type State (line 73) | public enum State {
    method refreshPreference (line 77) | @Override
Condensed preview — 27 files, each showing path, character count, and a content snippet. Download the .json file or copy for the full structured content (50K chars).
[
  {
    "path": ".gitignore",
    "chars": 71,
    "preview": "\n.gradle/\n.idea/\n*.iml\nbuild\nimport-summary.txt\nlocal.properties\n*.apk\n"
  },
  {
    "path": "README.md",
    "chars": 94,
    "preview": "# NoExclamation\n叹号杀手-去除安卓手机在国内时网络图标上的感叹号\n\nhttps://www.noisyfox.cn/android-captive-portal.html\n"
  },
  {
    "path": "app/build.gradle",
    "chars": 426,
    "preview": "apply plugin: 'com.android.application'\n\nandroid {\n    compileSdkVersion 28\n\n    defaultConfig {\n        applicationId \""
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "chars": 911,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n          pa"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/App.java",
    "chars": 453,
    "preview": "package org.foxteam.noisyfox.noexclamation;\n\nimport android.app.Application;\n\n//This class allows global method for Stri"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/NewActivity.java",
    "chars": 5504,
    "preview": "package org.foxteam.noisyfox.noexclamation;\n\nimport android.app.AlertDialog;\nimport android.app.ProgressDialog;\nimport a"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/Utils.java",
    "chars": 1774,
    "preview": "package org.foxteam.noisyfox.noexclamation;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.i"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/CommonConfigProvider.java",
    "chars": 3191,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport an"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/ConfigAdapterFactory.java",
    "chars": 3336,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter;\n\nimport android.content.Context;\nimport android.provider.Settings;\n\n"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/IConfigProvider.java",
    "chars": 324,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter;\n\nimport android.preference.PreferenceCategory;\n\n/**\n * Created by No"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/ITaskExecutor.java",
    "chars": 366,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter;\n\nimport android.os.Bundle;\n\n/**\n * Created by Noisyfox on 2017/7/1.\n"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/BaseSettingsItem.java",
    "chars": 831,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter.settings;\n\nimport org.foxteam.noisyfox.noexclamation.adapter.ITaskExe"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/GlobalKeyedSettings.java",
    "chars": 1881,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter.settings;\n\nimport android.os.Bundle;\n\nimport org.foxteam.noisyfox.noe"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ISettingsItem.java",
    "chars": 733,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter.settings;\n\nimport android.content.Context;\nimport android.os.Bundle;\n"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ListSettings.java",
    "chars": 2283,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter.settings;\n\nimport android.content.Context;\nimport android.os.Bundle;\n"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/TextSettings.java",
    "chars": 1930,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter.settings;\n\nimport android.content.Context;\nimport android.os.Bundle;\n"
  },
  {
    "path": "app/src/main/java/org/foxteam/noisyfox/noexclamation/adapter/settings/ToggleSettings.java",
    "chars": 3240,
    "preview": "package org.foxteam.noisyfox.noexclamation.adapter.settings;\n\nimport android.content.Context;\nimport android.os.Bundle;\n"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "chars": 2489,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">叹号杀手</string>\n    <string name=\"app_versi"
  },
  {
    "path": "app/src/main/res/values-en/strings.xml",
    "chars": 2910,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <!--\n    English Translation\n    by Bryan Walsh\n    (https://gith"
  },
  {
    "path": "app/src/main/res/values-zh/strings.xml",
    "chars": 2419,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"app_name\">叹号杀手</string>\n\n    <string name=\"setting_"
  },
  {
    "path": "app/src/main/res/xml/main_pref.xml",
    "chars": 1889,
    "preview": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\">\n   "
  },
  {
    "path": "build.gradle",
    "chars": 335,
    "preview": "// Top-level build file where you can add configuration options common to all sub-projects/modules.\nbuildscript {\n    re"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "chars": 234,
    "preview": "#Mon Mar 18 10:14:12 AEDT 2019\ndistributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\nzipStoreBase=GRADLE_USER"
  },
  {
    "path": "gradlew",
    "chars": 4971,
    "preview": "#!/usr/bin/env bash\n\n##############################################################################\n##\n##  Gradle start "
  },
  {
    "path": "gradlew.bat",
    "chars": 2314,
    "preview": "@if \"%DEBUG%\" == \"\" @echo off\n@rem ##########################################################################\n@rem\n@rem "
  },
  {
    "path": "settings.gradle",
    "chars": 15,
    "preview": "include ':app'\n"
  }
]

// ... and 1 more files (download for full content)

About this extraction

This page contains the full source code of the Noisyfox/NoExclamation GitHub repository, extracted and formatted as plain text for AI agents and large language models (LLMs). The extraction includes 27 files (43.9 KB), approximately 11.4k tokens, and a symbol index with 75 extracted functions, classes, methods, constants, and types. Use this with OpenClaw, Claude, ChatGPT, Cursor, Windsurf, or any other AI tool that accepts text input. You can copy the full output to your clipboard or download it as a .txt file.

Extracted by GitExtract — free GitHub repo to text converter for AI. Built by Nikandr Surkov.

Copied to clipboard!