Java tutorial
package eu.faircode.netguard; /* This file is part of NetGuard. NetGuard is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. NetGuard is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with NetGuard. If not, see <http://www.gnu.org/licenses/>. Copyright 2015-2016 by Marcel Bokhorst (M66B) */ import android.annotation.TargetApi; import android.app.job.JobInfo; import android.app.job.JobParameters; import android.app.job.JobScheduler; import android.app.job.JobService; import android.content.ComponentName; import android.content.Context; import android.content.SharedPreferences; import android.content.pm.PackageManager; import android.content.res.Configuration; import android.content.res.Resources; import android.os.AsyncTask; import android.os.Build; import android.os.PersistableBundle; import android.provider.Settings; import android.util.Log; import org.json.JSONObject; import java.io.BufferedOutputStream; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStream; import java.net.URL; import java.util.Date; import java.util.Locale; import javax.net.ssl.HttpsURLConnection; @TargetApi(Build.VERSION_CODES.LOLLIPOP) public class ServiceJob extends JobService { private static int id = 0; private static final String TAG = "NetGuard.Job"; private static final String cUrl = "https://crowd.netguard.me/"; private static final int cTimeOutMs = 15000; @Override public boolean onStartJob(JobParameters params) { Log.i(TAG, "Start job=" + params.getJobId()); new AsyncTask<JobParameters, Object, Object>() { @Override protected JobParameters doInBackground(JobParameters... params) { Log.i(TAG, "Executing job=" + params[0].getJobId()); HttpsURLConnection urlConnection = null; try { String android_id = Settings.Secure.getString(getContentResolver(), Settings.Secure.ANDROID_ID); JSONObject json = new JSONObject(); json.put("device", Util.sha256(android_id, "")); json.put("product", Build.DEVICE); json.put("sdk", Build.VERSION.SDK_INT); json.put("country", Locale.getDefault().getCountry()); json.put("netguard", Util.getSelfVersionCode(ServiceJob.this)); try { json.put("store", getPackageManager().getInstallerPackageName(getPackageName())); } catch (Throwable ex) { Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex)); json.put("store", null); } for (String name : params[0].getExtras().keySet()) json.put(name, params[0].getExtras().get(name)); urlConnection = (HttpsURLConnection) new URL(cUrl).openConnection(); urlConnection.setConnectTimeout(cTimeOutMs); urlConnection.setReadTimeout(cTimeOutMs); urlConnection.setRequestProperty("Accept", "application/json"); urlConnection.setRequestProperty("Content-type", "application/json"); urlConnection.setRequestMethod("POST"); urlConnection.setDoInput(true); urlConnection.setDoOutput(true); OutputStream out = new BufferedOutputStream(urlConnection.getOutputStream()); out.write(json.toString().getBytes()); // UTF-8 out.flush(); int code = urlConnection.getResponseCode(); if (code != HttpsURLConnection.HTTP_OK) throw new IOException("HTTP " + code); InputStreamReader isr = new InputStreamReader(urlConnection.getInputStream()); Log.i(TAG, "Response=" + Util.readString(isr).toString()); jobFinished(params[0], false); if ("rule".equals(params[0].getExtras().getString("type"))) { SharedPreferences history = getSharedPreferences("history", Context.MODE_PRIVATE); history.edit().putLong(params[0].getExtras().getString("package") + ":submitted", new Date().getTime()).apply(); } } catch (Throwable ex) { Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex)); jobFinished(params[0], true); } finally { if (urlConnection != null) urlConnection.disconnect(); try { Thread.sleep(1000); } catch (InterruptedException ignored) { } } return null; } }.execute(params); return true; } @Override public boolean onStopJob(JobParameters params) { Log.i(TAG, "Stop job=" + params.getJobId()); return true; } public static void submit(Rule rule, Context context) { PersistableBundle bundle = new PersistableBundle(); bundle.putString("type", "rule"); bundle.putInt("wifi_default", rule.wifi_default ? 1 : 0); bundle.putInt("other_default", rule.other_default ? 1 : 0); bundle.putInt("screen_wifi_default", rule.screen_wifi_default ? 1 : 0); bundle.putInt("screen_other_default", rule.screen_other_default ? 1 : 0); bundle.putInt("roaming_default", rule.roaming_default ? 1 : 0); bundle.putInt("wifi_blocked", rule.wifi_blocked ? 1 : 0); bundle.putInt("other_blocked", rule.other_blocked ? 1 : 0); bundle.putInt("screen_wifi", rule.screen_wifi ? 1 : 0); bundle.putInt("screen_other", rule.screen_other ? 1 : 0); bundle.putInt("roaming", rule.roaming ? 1 : 0); bundle.putInt("apply", rule.apply ? 1 : 0); bundle.putInt("notify", rule.notify ? 1 : 0); submit(rule, bundle, context); } public static void submit(Rule rule, int version, int protocol, String daddr, int dport, int blocked, Context context) { PersistableBundle bundle = new PersistableBundle(); bundle.putString("type", "host"); bundle.putInt("version", version); bundle.putInt("protocol", protocol); bundle.putString("daddr", daddr); bundle.putInt("dport", dport); bundle.putInt("blocked", blocked); submit(rule, bundle, context); } private static void submit(Rule rule, PersistableBundle bundle, Context context) { PackageManager pm = context.getPackageManager(); JobScheduler scheduler = (JobScheduler) context.getSystemService(Context.JOB_SCHEDULER_SERVICE); // Get english application label String label = null; try { Configuration config = new Configuration(); config.setLocale(new Locale("en")); Resources res = pm.getResourcesForApplication(rule.info.packageName); res.updateConfiguration(config, res.getDisplayMetrics()); label = res.getString(rule.info.applicationInfo.labelRes); } catch (Throwable ex) { Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex)); CharSequence cs = rule.info.applicationInfo.loadLabel(pm); if (cs != null) label = cs.toString(); } // Add application data bundle.putInt("uid", rule.info.applicationInfo.uid); bundle.putString("package", rule.info.packageName); bundle.putInt("version_code", rule.info.versionCode); bundle.putString("version_name", rule.info.versionName); bundle.putString("label", label); bundle.putInt("system", rule.system ? 1 : 0); try { bundle.putString("installer", pm.getInstallerPackageName(rule.info.packageName)); } catch (Throwable ex) { Log.e(TAG, ex.toString() + "\n" + Log.getStackTraceString(ex)); bundle.putString("installer", null); } // Cancel overlapping jobs for (JobInfo pending : scheduler.getAllPendingJobs()) { String type = pending.getExtras().getString("type"); if (type != null && type.equals(bundle.getString("type"))) { if (type.equals("rule")) { int uid = pending.getExtras().getInt("uid"); if (uid == bundle.getInt("uid")) { Log.i(TAG, "Canceling id=" + pending.getId()); scheduler.cancel(pending.getId()); } } else if (type.equals("host")) { int uid = pending.getExtras().getInt("uid"); int version = pending.getExtras().getInt("version"); int protocol = pending.getExtras().getInt("protocol"); String daddr = pending.getExtras().getString("daddr"); int dport = pending.getExtras().getInt("dport"); if (uid == bundle.getInt("uid") && version == bundle.getInt("version") && protocol == bundle.getInt("protocol") && daddr != null && daddr.equals(bundle.getString("daddr")) && dport == bundle.getInt("dport")) { Log.i(TAG, "Canceling id=" + pending.getId()); scheduler.cancel(pending.getId()); } } } } // Schedule job ComponentName serviceName = new ComponentName(context, ServiceJob.class); JobInfo job = new JobInfo.Builder(++id, serviceName).setRequiredNetworkType(JobInfo.NETWORK_TYPE_UNMETERED) .setMinimumLatency(Util.isDebuggable(context) ? 10 * 1000 : 60 * 1000).setExtras(bundle) .setPersisted(true).build(); if (scheduler.schedule(job) == JobScheduler.RESULT_SUCCESS) Log.i(TAG, "Scheduled job=" + job.getId() + " success"); else Log.e(TAG, "Scheduled job=" + job.getId() + " failed"); } }