Deben Oldert vor 10 Jahren
Ursprung
Commit
4f0af4c4bf
48 geänderte Dateien mit 1339 neuen und 0 gelöschten Zeilen
  1. 68 0
      Android app/AndroidManifest.xml
  2. BIN
      Android app/Export/Access control.apk
  3. 47 0
      Android app/java/com/dev/deben/implementation/GcmService.java
  4. 41 0
      Android app/java/com/dev/deben/implementation/InstanceIdService.java
  5. 209 0
      Android app/java/com/dev/deben/implementation/LoginActivity.java
  6. 189 0
      Android app/java/com/dev/deben/implementation/MainActivity.java
  7. 88 0
      Android app/java/com/dev/deben/implementation/RegisterIntentService.java
  8. 365 0
      Android app/java/com/dev/deben/implementation/function.java
  9. BIN
      Android app/logo-web.png
  10. BIN
      Android app/res/drawable-hdpi-v11/noti_logo.png
  11. BIN
      Android app/res/drawable-hdpi-v9/noti_logo.png
  12. BIN
      Android app/res/drawable-hdpi/action_logo.png
  13. BIN
      Android app/res/drawable-hdpi/noti_logo.png
  14. BIN
      Android app/res/drawable-mdpi-v11/noti_logo.png
  15. BIN
      Android app/res/drawable-mdpi-v9/noti_logo.png
  16. BIN
      Android app/res/drawable-mdpi/action_logo.png
  17. BIN
      Android app/res/drawable-mdpi/noti_logo.png
  18. BIN
      Android app/res/drawable-xhdpi-v11/noti_logo.png
  19. BIN
      Android app/res/drawable-xhdpi-v9/noti_logo.png
  20. BIN
      Android app/res/drawable-xhdpi/action_logo.png
  21. BIN
      Android app/res/drawable-xhdpi/noti_logo.png
  22. BIN
      Android app/res/drawable-xxhdpi-v11/noti_logo.png
  23. BIN
      Android app/res/drawable-xxhdpi-v9/noti_logo.png
  24. BIN
      Android app/res/drawable-xxhdpi/action_logo.png
  25. BIN
      Android app/res/drawable-xxhdpi/noti_logo.png
  26. 71 0
      Android app/res/layout/activity_login.xml
  27. 54 0
      Android app/res/layout/activity_main.xml
  28. 7 0
      Android app/res/menu/menu_access.xml
  29. 7 0
      Android app/res/menu/menu_login.xml
  30. 6 0
      Android app/res/menu/menu_main.xml
  31. BIN
      Android app/res/mipmap-hdpi/ic_launcher.png
  32. BIN
      Android app/res/mipmap-hdpi/logo.png
  33. BIN
      Android app/res/mipmap-mdpi/ic_launcher.png
  34. BIN
      Android app/res/mipmap-mdpi/logo.png
  35. BIN
      Android app/res/mipmap-xhdpi/ic_launcher.png
  36. BIN
      Android app/res/mipmap-xhdpi/logo.png
  37. BIN
      Android app/res/mipmap-xxhdpi/ic_launcher.png
  38. BIN
      Android app/res/mipmap-xxhdpi/logo.png
  39. BIN
      Android app/res/mipmap-xxxhdpi/logo.png
  40. 6 0
      Android app/res/values-w820dp/dimens.xml
  41. 5 0
      Android app/res/values/dimens.xml
  42. 9 0
      Android app/res/values/strings.xml
  43. 61 0
      Android app/res/values/strings_activity_settings.xml
  44. 8 0
      Android app/res/values/styles.xml
  45. 21 0
      Android app/res/xml/pref_data_sync.xml
  46. 33 0
      Android app/res/xml/pref_general.xml
  47. 17 0
      Android app/res/xml/pref_headers.xml
  48. 27 0
      Android app/res/xml/pref_notification.xml

+ 68 - 0
Android app/AndroidManifest.xml

@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="utf-8"?>
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+    package="com.dev.deben.implementation" >
+
+
+
+    <uses-permission android:name="android.permission.INTERNET" />
+    <uses-permission android:name="android.permission.WAKE_LOCK" />
+    <uses-permission android:name="android.permission.VIBRATE" />
+    <uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
+    <uses-permission android:name="com.dev.deben.implementation.permission.C2D_MESSAGE" />
+    <permission android:name="com.dev.deben.implementation.permission.C2D_MESSAGE"
+    android:protectionLevel="signature" />
+
+    <application
+        android:allowBackup="false"
+        android:fullBackupContent="false"
+        android:icon="@mipmap/logo"
+        android:label="@string/app_name"
+        android:theme="@style/AppTheme">
+        <activity
+            android:name=".LoginActivity"
+            android:label="Register Device" >
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN" />
+                <category android:name="android.intent.category.LAUNCHER" />
+                <action android:name="android.intent.action.VIEW" />
+                <category android:name="android.intent.category.DEFAULT" />
+                <category android:name="android.intent.category.BROWSABLE" />
+                <data android:scheme="http"
+                    android:host="www.implementation.deben.dev"
+                    android:path="/Login"/>
+            </intent-filter>
+        </activity>
+        <activity
+            android:name=".MainActivity"
+            android:label="Answer access request" >
+        </activity>
+        <receiver
+            android:name="com.google.android.gms.gcm.GcmReceiver"
+            android:exported="true"
+            android:permission="com.google.android.c2dm.permission.SEND" >
+            <intent-filter>
+                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
+                <category android:name="com.example.gcm" />
+            </intent-filter>
+        </receiver>
+        <service
+            android:name=".GcmService"
+            android:exported="false" >
+            <intent-filter>
+                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
+            </intent-filter>
+        </service>
+        <service
+            android:name=".InstanceIdService"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="com.google.android.gms.iid.InstanceID"/>
+            </intent-filter>
+        </service>
+        <service
+            android:name=".RegisterIntentService"
+            android:exported="false">
+        </service>
+    </application>
+
+</manifest>

BIN
Android app/Export/Access control.apk


+ 47 - 0
Android app/java/com/dev/deben/implementation/GcmService.java

@@ -0,0 +1,47 @@
+/*
+Copyright 2015 Google Inc. All Rights Reserved.
+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 com.dev.deben.implementation;
+
+import android.os.Bundle;
+import android.os.SystemClock;
+
+import com.google.android.gms.gcm.GcmListenerService;
+
+import org.json.JSONException;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+
+
+/**
+ * Service used for receiving GCM messages. When a message is received this service will log it.
+ */
+public class GcmService extends GcmListenerService {
+
+    function fn = new function(this);
+
+    @Override
+    public void onMessageReceived(String from, Bundle data) {
+        System.out.println("Msg from: " + from + ", " + data);
+        try {
+            fn.writeSetting("requestId", data.getString("requestId"));
+        } catch (IOException | JSONException e) {
+            e.printStackTrace();
+        }
+        int id = fn.notifier(from, "New VPN login request");
+        SystemClock.sleep(30000);
+        fn.cancelNotify(id);
+    }
+
+}

+ 41 - 0
Android app/java/com/dev/deben/implementation/InstanceIdService.java

@@ -0,0 +1,41 @@
+package com.dev.deben.implementation;
+
+import com.google.android.gms.gcm.GoogleCloudMessaging;
+import com.google.android.gms.iid.InstanceIDListenerService;
+import com.google.android.gms.iid.InstanceID;
+
+import org.json.JSONException;
+
+import java.io.IOException;
+import java.util.HashMap;
+import android.content.Context;
+
+/**
+ * Created by Deben on 22-10-15.
+ */
+public class InstanceIdService extends InstanceIDListenerService {
+    Context ctx = this;
+
+
+
+
+    function fn = new function(ctx);
+
+    public String getIid() {
+        return InstanceID.getInstance(ctx).getId().toString();
+    }
+
+    public String getToken() throws IOException {
+        return "";
+        /*String authEntity = "implementation-51b96";
+        String scope = "GCM";
+        System.out.println("GENERATING TOKEN");
+        try {
+            return InstanceID.getInstance(ctx).getToken("implementation-51b96", "GCM").toString();
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+        return "";*/
+    }
+
+};

+ 209 - 0
Android app/java/com/dev/deben/implementation/LoginActivity.java

@@ -0,0 +1,209 @@
+package com.dev.deben.implementation;
+
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.EditText;
+import android.widget.TextView;
+import android.app.ProgressDialog;
+
+import org.json.JSONException;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+import java.util.HashMap;
+import android.os.StrictMode;
+import com.google.android.gms.common.ConnectionResult;
+import com.google.android.gms.common.GoogleApiAvailability;
+
+public class LoginActivity extends AppCompatActivity {
+
+    function fn = new function(this);
+    TextView error;
+    Button login;
+    String regCode;
+    EditText userField;
+    EditText passField;
+    EditText codeField;
+
+    @Override
+    public void onBackPressed() {
+    }
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_login);
+
+        error = (TextView) findViewById(R.id.error);
+        error.setVisibility(View.INVISIBLE);
+        login = (Button) findViewById(R.id.login);
+        userField = (EditText) findViewById(R.id.username);
+        passField = (EditText) findViewById(R.id.password);
+        codeField = (EditText) findViewById(R.id.regCode);
+
+        Uri param = getIntent().getData();
+
+        if(param != null) {
+            System.out.println("URI=" + param.toString());
+            if (param.getQueryParameter("rid") != null) {
+                HashMap<String, String> set = new HashMap<>();
+                set.put("requestId", param.getQueryParameter("rid"));
+                try {
+                    fn.writeSetting(set);
+                } catch (IOException | JSONException e) {
+                    e.printStackTrace();
+                }
+            }
+            if (param.getQueryParameter("rcd") != null) {
+                codeField.setText(param.getQueryParameter("rcd"));
+            }
+        }
+
+        if (android.os.Build.VERSION.SDK_INT > 9) {
+            StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
+            StrictMode.setThreadPolicy(policy);
+        }
+        if(checkPlayServices()) {
+            Intent intent = new Intent(this, RegisterIntentService.class);
+            startService(intent);
+        }
+
+        try {
+            fn.init();
+            if(!fn.readSetting("username").equals("") && !fn.readSetting("registerCode").equals("")) {
+                if(fn.checkRegCode(fn.readSetting("registerCode"), fn.readSetting("username"))) {
+                    //USER ALREADY LOGGED IN
+                    fn.redirect("Main");
+                }
+                else {
+                    //NO LOGIN
+                }
+            }
+
+
+
+        } catch (IOException | JSONException e) {
+            e.printStackTrace();
+        }
+
+        Button button = (Button) findViewById(R.id.login);
+        button.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+
+
+
+                try {
+                    login(userField.getText().toString(), passField.getText().toString(), codeField.getText().toString());
+                } catch (IOException | JSONException e) {
+                    e.printStackTrace();
+                }
+
+            }
+        });
+    }
+
+    private void login(String username, String password, String code) throws IOException, JSONException {
+        error.setVisibility(View.INVISIBLE);
+        error.setText("");
+        if(username == null || username.equals("") && username.length() < 5) {
+            error.setText("Username too short");
+            error.setVisibility(View.VISIBLE);
+            return;
+        }
+        if(password == null || password.equals("") && password.length() < 5) {
+            error.setText("Password too short");
+            error.setVisibility(View.VISIBLE);
+            return;
+        }
+        if(code == null || code.equals("") || code.length() != 4) {
+            error.setText("Invalid register code");
+            error.setVisibility(View.VISIBLE);
+            return;
+        }
+
+            ProgressDialog progress = new ProgressDialog(this);
+            progress.setTitle("Registering");
+            progress.setMessage("Processing request...");
+            progress.setCancelable(false);
+            progress.show();
+
+            JSONObject info = new JSONObject();
+            info.put("serviceType", "GCM");
+            info.put("serviceNumber", fn.readSetting("serviceNumber"));
+            info.put("deviceId", fn.readSetting("deviceId"));
+            info.put("notificationId", fn.readSetting("notificationId"));
+            info.put("apiKey", fn.readSetting("apiKey"));
+
+
+            JSONObject json = new JSONObject();
+            json.put("function", "register");
+            json.put("requestId", fn.readSetting("requestId"));
+            json.put("registerCode", code);
+            json.put("username", username);
+            json.put("password", password);
+            json.put("userInfo", info);
+
+            StringWriter out = new StringWriter();
+            json.writeJSONString(out);
+
+            String response = fn.makeRequest("GET", fn.readSetting("serverUrl"), out.toString());
+            System.out.println(response);
+            if(response.length() == 0 || response == null || response == "") {
+                progress.dismiss();
+                error.setText("Request Failed. Try again later");
+                error.setVisibility(View.VISIBLE);
+                return;
+            }
+            else {
+                Object obj = JSONValue.parse(response);
+                JSONObject res = (JSONObject) obj;
+                if(res.get("result").equals("0") || Integer.parseInt(res.get("result").toString()) == 0) {
+
+                    HashMap<String, String> set = new HashMap<>();
+                    set.put("username", username);
+                    set.put("password", password);
+                    set.put("registerCode", code);
+                    set.put("requestId", "0");
+                    fn.writeSetting(set);
+                    progress.dismiss();
+                    fn.redirect("Main");
+                }
+                else {
+                    progress.dismiss();
+                    error.setText("Error "+res.get("result")+": "+res.get("resultText"));
+                    error.setVisibility(View.VISIBLE);
+                    return;
+                }
+            }
+            return;
+    }
+    private boolean checkPlayServices() {
+        GoogleApiAvailability apiAvailability = GoogleApiAvailability.getInstance();
+        int resultCode = apiAvailability.isGooglePlayServicesAvailable(this);
+        if (resultCode != ConnectionResult.SUCCESS) {
+            if (apiAvailability.isUserResolvableError(resultCode)) {
+                apiAvailability.getErrorDialog(this, resultCode, 9000)
+                        .show();
+                error.setText("Service must be up to date in order to use this app");
+                error.setVisibility(View.VISIBLE);
+                login.setEnabled(false);
+            } else {
+                error.setText("Device not supported");
+                error.setVisibility(View.VISIBLE);
+                login.setEnabled(false);
+                finish();
+            }
+            return false;
+        }
+        return true;
+    }
+}

+ 189 - 0
Android app/java/com/dev/deben/implementation/MainActivity.java

@@ -0,0 +1,189 @@
+package com.dev.deben.implementation;
+
+import android.app.ProgressDialog;
+import android.graphics.Color;
+import android.support.v7.app.AppCompatActivity;
+import android.os.Bundle;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+import android.widget.Button;
+import android.widget.TextView;
+
+import org.json.JSONException;
+import org.json.simple.JSONObject;
+import org.json.simple.JSONValue;
+
+import java.io.IOException;
+import java.io.StringWriter;
+
+
+public class MainActivity extends AppCompatActivity {
+
+    function fn = new function(this);
+    public boolean active = true;
+    Button accept;
+    Button deny;
+    TextView status;
+    TextView desc;
+
+    @Override
+    public void onBackPressed() {
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        active = false;
+    }
+    @Override
+    public void onResume() {
+        super.onResume();
+        active = true;
+        accept = (Button) findViewById(R.id.Accept);
+        deny = (Button) findViewById(R.id.Deny);
+        status = (TextView) findViewById(R.id.status);
+        desc = (TextView) findViewById(R.id.descriptor);
+        try {
+            if(fn.readSetting("requestId").equals("0")) {
+                desc.setText(R.string.No_req);
+                accept.setEnabled(false);
+                deny.setEnabled(false);
+            }
+            else {
+                desc.setText(R.string.req);
+                accept.setEnabled(true);
+                deny.setEnabled(true);
+            }
+        } catch (JSONException | IOException e) {
+            e.printStackTrace();
+        }
+    }
+
+
+    @Override
+    protected void onCreate(Bundle savedInstanceState) {
+
+        super.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+
+
+        accept = (Button) findViewById(R.id.Accept);
+        deny = (Button) findViewById(R.id.Deny);
+        status = (TextView) findViewById(R.id.status);
+        try {
+            if(fn.readSetting("requestId").equals("0")) {
+                status.setText("@string/No_req");
+                accept.setEnabled(false);
+                deny.setEnabled(false);
+            }
+            else {
+                status.setText("@string/req");
+                accept.setEnabled(true);
+                deny.setEnabled(true);
+            }
+        } catch (JSONException | IOException e) {
+            e.printStackTrace();
+        }
+
+
+        accept.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    buildReply(true, accept, deny);
+                } catch (JSONException | IOException e) {
+                    e.printStackTrace();
+                }
+
+            }
+        });
+        deny.setOnClickListener(new View.OnClickListener() {
+            @Override
+            public void onClick(View v) {
+                try {
+                    buildReply(false, accept, deny);
+                } catch (JSONException | IOException e) {
+                    e.printStackTrace();
+                }
+            }
+        });
+    }
+
+    @Override
+    public boolean onCreateOptionsMenu(Menu menu) {
+
+       menu.add("Unregister");
+
+        return super.onCreateOptionsMenu(menu);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        System.out.println(item.getItemId());
+        switch(item.getItemId()) {
+            case 0:
+                try {
+                    fn.logout();
+                } catch (IOException | JSONException e) {
+                    e.printStackTrace();
+                }
+                break;
+        }
+        return true;
+
+    }
+
+
+
+    private void buildReply(boolean grand, Button accept, Button deny) throws JSONException, IOException {
+        accept.setEnabled(false);
+        deny.setEnabled(false);
+
+        ProgressDialog progress = new ProgressDialog(this);
+        progress.setTitle((grand ? "Approving" : "Cancelling") + " request");
+        progress.setMessage("Processing...");
+        progress.setCancelable(false);
+        progress.show();
+
+        JSONObject json = new JSONObject();
+        json.put("function", "confirm");
+        json.put("requestId", fn.readSetting("requestId"));
+        json.put("deviceId", fn.readSetting("deviceId"));
+        json.put("apiKey", fn.readSetting("apiKey"));
+        json.put("notificationId", fn.readSetting("notificationId"));
+        json.put("confirmation", grand ? "approved" : "cancelled");
+
+        StringWriter out = new StringWriter();
+        json.writeJSONString(out);
+
+        String response = fn.makeRequest("POST", fn.readSetting("serverUrl"), out.toString());
+        Object obj = JSONValue.parse(response);
+        JSONObject res = (JSONObject) obj;
+
+
+
+        if(res.get("result").equals("0") || Integer.parseInt(res.get("result").toString()) == 0) {
+            status.setText("VPN request successfully " + (grand ? "APPROVED" : "CANCELLED"));
+            if(grand) {
+                status.setTextColor(Color.parseColor("#04ff00"));
+            }
+            else {
+                status.setTextColor(Color.parseColor("#DF7401"));
+            }
+            fn.writeSetting("requestId", "0");
+        }
+        else {
+            status.setText("Something went wrong, " + res.get("result").toString() + "\n" + res.get("resultText").toString());
+            status.setTextColor(Color.parseColor("#ff1700"));
+        }
+        status.setVisibility(View.VISIBLE);
+        accept.setEnabled(true);
+        deny.setEnabled(true);
+
+        progress.dismiss();
+    }
+
+
+}

+ 88 - 0
Android app/java/com/dev/deben/implementation/RegisterIntentService.java

@@ -0,0 +1,88 @@
+/**
+ * Copyright 2015 Google Inc. All Rights Reserved.
+ *
+ * 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 com.dev.deben.implementation;
+
+import android.app.IntentService;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.preference.PreferenceManager;
+import android.support.v4.content.LocalBroadcastManager;
+import android.util.Log;
+
+import com.google.android.gms.gcm.GcmPubSub;
+import com.google.android.gms.gcm.GoogleCloudMessaging;
+import com.google.android.gms.iid.InstanceID;
+
+import org.json.JSONException;
+
+import java.io.IOException;
+import java.util.HashMap;
+
+public class RegisterIntentService extends IntentService {
+
+    private static final String TAG = "RegIntentService";
+
+    public RegisterIntentService() {
+        super(TAG);
+    }
+    function fn = new function(this);
+
+    @Override
+    protected void onHandleIntent(Intent intent) {
+
+        try {
+            // [START register_for_gcm]
+            // Initially this call goes out to the network to retrieve the token, subsequent calls
+            // are local.
+            // [START get_token]
+            InstanceID instanceID = InstanceID.getInstance(this);
+            // R.string.gcm_defaultSenderId (the Sender ID) is typically derived from google-services.json.
+            // See https://developers.google.com/cloud-messaging/android/start for details on this file.
+            String token = instanceID.getToken(getString(R.string.gcm_defaultSenderId),
+                    GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
+            // [END get_token]
+           // Log.i(TAG, "GCM Registration Token: " + token);
+            System.out.println("Service creating token");
+            System.out.println("Token: "+token);
+
+            sendRegistrationToServer(token);
+
+            // [END register_for_gcm]
+        } catch (Exception e) {
+            System.out.println("Failed to complete token refresh");
+        }
+
+    }
+
+    /**
+     * Persist registration to third-party servers.
+     *
+     * Modify this method to associate the user's GCM registration token with any server-side account
+     * maintained by your application.
+     *
+     * @param token The new token.
+     */
+    private void sendRegistrationToServer(String token) throws IOException, JSONException {
+        System.out.println("REGISTERING TOKEN");
+
+        HashMap<String, String> set = new HashMap<>();
+        set.put("notificationId", token);
+        fn.writeSetting(set);
+    }
+
+
+}

+ 365 - 0
Android app/java/com/dev/deben/implementation/function.java

@@ -0,0 +1,365 @@
+package com.dev.deben.implementation;
+
+import org.json.JSONException;
+//import org.json.JSONObject;
+import org.json.simple.JSONValue;
+import org.json.simple.JSONObject;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStreamReader;
+import java.io.OutputStreamWriter;
+import java.util.HashMap;
+
+import android.app.Notification;
+import android.app.NotificationManager;
+import android.content.ContextWrapper;
+import android.content.Context;
+import android.content.Intent;
+import android.util.Log;
+import android.widget.EditText;
+import android.widget.Toast;
+import java.io.StringWriter;
+import java.util.Map;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.io.DataOutputStream;
+
+import android.provider.Settings.Secure;
+import com.google.android.gms.common.GoogleApiAvailability;
+import com.google.android.gms.common.ConnectionResult;
+
+import com.google.android.gms.gcm.GoogleCloudMessaging;
+import com.google.android.gms.iid.InstanceID;
+import android.support.v4.app.NotificationCompat;
+import android.app.TaskStackBuilder;
+import android.app.PendingIntent;
+import android.app.NotificationManager;
+import android.content.Context;
+
+/**
+ * Created by Deben on 21-10-15.
+ */
+public class function {
+    private static Context ctx;
+    private static String settings;
+    private static String file = "settings.json";
+
+    function(Context init) {
+        ctx = init;
+    }
+
+    public boolean writeSetting(HashMap<String, String> set) throws IOException, JSONException {
+        String jsonText = settingFile();
+        //System.out.println("JSON WRITE BEFORE: "+jsonText);
+        if(jsonText != null) {
+            Object obj = JSONValue.parse(jsonText);
+            JSONObject json = (JSONObject) obj;
+            for(Map.Entry<String, String> entry : set.entrySet()) {
+                json.put(entry.getKey(), entry.getValue());
+            }
+
+            FileOutputStream fout = ctx.openFileOutput(file, ctx.MODE_PRIVATE);
+            OutputStreamWriter outwr = new OutputStreamWriter(fout);
+
+            StringWriter out = new StringWriter();
+            json.writeJSONString(out);
+
+            String txt = out.toString();
+            settings = txt;
+
+            outwr.write(txt);
+            outwr.close();
+            //System.out.println("JSON WRITE AFTER: " + txt);
+            return true;
+        }
+        else{
+            //System.out.println("JSON WRITE NULL");
+            return false;
+        }
+    }
+    public boolean writeSetting(String key, String value) throws IOException, JSONException {
+        String jsonText = settingFile();
+        if(jsonText != null) {
+            Object obj = JSONValue.parse(jsonText);
+            JSONObject json = (JSONObject) obj;
+            json.put(key, value);
+
+            FileOutputStream fout = ctx.openFileOutput(file, ctx.MODE_PRIVATE);
+            OutputStreamWriter outwr = new OutputStreamWriter(fout);
+
+            StringWriter out = new StringWriter();
+            json.writeJSONString(out);
+
+            String txt = out.toString();
+            settings = txt;
+
+            outwr.write(txt);
+            outwr.close();
+            return true;
+        }
+        else{
+            return false;
+        }
+    }
+    public void init() throws IOException, JSONException {
+        settings = settingFile();
+        System.out.println("INIT START");
+        Object obj = JSONValue.parse(settings);
+        JSONObject json = (JSONObject) obj;
+        if(json.get("apiKey").equals("")) {
+            System.out.println("INIT CREATE");
+
+            Intent intent = new Intent(ctx, InstanceIdService.class);
+            ctx.startService(intent);
+
+            //InstanceIdService srv = new InstanceIdService();
+
+            //HashMap<String, String> set = new HashMap<>();
+            //set.put("apiKey", srv.getToken());
+
+            //System.out.println("TOKEN: "+srv.getToken());
+
+            //writeSetting(set);
+
+            settings = settingFile();
+        }
+        System.out.println("INIT STOP");
+    }
+
+    public String readSetting(String key) throws JSONException, IOException {
+            Object obj = JSONValue.parse(settings);
+            JSONObject json = (JSONObject) obj;
+            String value = null;
+            if (json.get(key) != null) {
+                value = (String) json.get(key);
+            }
+            return value;
+    }
+    public void logout() throws IOException, JSONException {
+        JSONObject json = new JSONObject();
+        json.put("function", "unregister");
+        json.put("username", readSetting("username"));
+        json.put("password", readSetting("password"));
+        json.put("registerCode", readSetting("registerCode"));
+        json.put("requestId", "0");
+
+        makeRequest("POST", readSetting("serverUrl"), json.toJSONString());
+
+        System.out.println("Logging out");
+        File del = new File(ctx.getFilesDir().getAbsolutePath(), file);
+        del.delete();
+        redirect("Login");
+    }
+
+    private String settingFile() throws IOException, JSONException {
+        ContextWrapper cw = new ContextWrapper(ctx);
+
+        String jsonStr = null;
+
+        System.out.println("Trying to read settings");
+
+        try {
+            FileInputStream fin = ctx.openFileInput(file);
+            BufferedReader rd = new BufferedReader(new InputStreamReader(fin));
+            StringBuilder sb = new StringBuilder();
+            String line = null;
+            while ((line = rd.readLine()) != null) {
+                sb.append(line);
+            }
+            jsonStr = sb.toString();
+            rd.close();
+            fin.close();
+            System.out.println("Read settings");
+        }
+        catch(IOException e){
+            FileOutputStream fout = ctx.openFileOutput(file, ctx.MODE_PRIVATE);
+            OutputStreamWriter outwr = new OutputStreamWriter(fout);
+
+            JSONObject json = new JSONObject();
+            json.put("serviceType", "GCM");
+            json.put("serviceNumber", "454250381809");
+            json.put("notificationId", "");
+            json.put("deviceId", Secure.getString(ctx.getContentResolver(), Secure.ANDROID_ID));
+            json.put("username", "");
+            json.put("password", "");
+            json.put("registerCode", "");
+            json.put("apiKey", "AIzaSyB67KpF-KSuZoPdnuy03TEIKRjHkBLEPpM");
+            json.put("serverUrl", "http://192.168.2.240:8080/Implementation/SAS");
+            json.put("requestId", "0");
+
+            StringWriter out = new StringWriter();
+            json.writeJSONString(out);
+
+            jsonStr = out.toString();
+
+            outwr.write(jsonStr);
+            outwr.close();
+        }
+        System.out.println("return settings: "+jsonStr);
+        return jsonStr;
+
+    }
+    private int getCharCode(String letter) {
+        letter = letter.toLowerCase();
+        switch(letter) {
+            case "a":
+                return 1;
+            case "b":
+                return 2;
+            case "c":
+                return 3;
+            case "d":
+                return 4;
+            case "e":
+                return 5;
+            case "f":
+                return 6;
+            case "g":
+                return 7;
+            case "h":
+                return 8;
+            case "i":
+                return 9;
+            case "j":
+                return 10;
+            case "k":
+                return 11;
+            case "l":
+                return 12;
+            case "m":
+                return 13;
+            case "n":
+                return 14;
+            case "o":
+                return 15;
+            case "p":
+                return 16;
+            case "q":
+                return 17;
+            case "r":
+                return 18;
+            case "s":
+                return 19;
+            case "t":
+                return 20;
+            case "u":
+                return 21;
+            case "v":
+                return 22;
+            case "w":
+                return 23;
+            case "x":
+                return 24;
+            case "y":
+                return 25;
+            case "z":
+                return 26;
+            default:
+                return 0;
+        }
+    }
+    public String genRegCode(String str) {
+        String first = str.substring(0, 1);
+        String last = str.substring(str.length()-1);
+        int firstCode = getCharCode(first);
+        int lastCode = getCharCode(last);
+
+        System.out.println("first: "+first+", "+firstCode);
+        System.out.println("first: "+last+", "+lastCode);
+
+        if(firstCode < 27 && firstCode > 0) {
+            first = ""+firstCode;
+        }
+        else {
+            return null;
+        }
+        if(lastCode < 27 && lastCode > 0) {
+            last = ""+lastCode;
+        }
+        else {
+            return null;
+        }
+        if(first.length() < 2) {
+            first = "0"+first;
+        }
+        if(last.length() < 2) {
+            last = "0"+last;
+        }
+        return first+last;
+    }
+    public boolean checkRegCode(String code, String str) {
+        String newCode = genRegCode(str);
+        return code.equals(newCode);
+    }
+
+    public String makeRequest(String type, String url, String body) throws IOException {
+        System.out.println(url);
+        System.out.println(body);
+        URL obj = new URL(url);
+        HttpURLConnection con = (HttpURLConnection) obj.openConnection();
+
+        con.setRequestMethod(type);
+                con.setRequestProperty("content-type", "application/json");
+
+                con.setDoOutput(true);
+                DataOutputStream wr = new DataOutputStream(con.getOutputStream());
+                wr.writeBytes(body);
+                wr.flush();
+                wr.close();
+
+                BufferedReader rd = new BufferedReader(new InputStreamReader(con.getInputStream()));
+                StringBuilder sb = new StringBuilder();
+                String line = null;
+                while ((line = rd.readLine()) != null) {
+                    sb.append(line);
+                }
+                String response = sb.toString();
+
+                rd.close();
+                con.disconnect();
+
+                return response;
+
+    }
+    public void redirect(String act) {
+        Intent intent;
+        switch(act) {
+            case "Main":
+                intent = new Intent(ctx, MainActivity.class);
+                break;
+            case "Login":
+                intent = new Intent(ctx, LoginActivity.class);
+                break;
+            default:
+                intent = new Intent(ctx, LoginActivity.class);
+        }
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+        ctx.startActivity(intent);
+    }
+    public int notifier(String title, String msg) {
+        System.out.println("BUILDING NOTIFICATION");
+        NotificationManager nMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
+        PendingIntent pi = PendingIntent.getActivity(ctx, 0, new Intent(ctx, MainActivity.class), 0);
+        int id = (int)System.currentTimeMillis();
+        Notification mBuilder = new NotificationCompat.Builder(ctx)
+                        .setSmallIcon(R.drawable.action_logo)
+                        .setContentTitle(title)
+                        .setContentText(msg)
+                        .setAutoCancel(true)
+                        .setContentIntent(pi)
+                        .build();
+        nMgr.notify(id, mBuilder);
+        return id;
+
+    }
+    public void cancelNotify(int id) {
+        NotificationManager nMgr = (NotificationManager) ctx.getSystemService(Context.NOTIFICATION_SERVICE);
+        nMgr.cancel(id);
+    }
+}

BIN
Android app/logo-web.png


BIN
Android app/res/drawable-hdpi-v11/noti_logo.png


BIN
Android app/res/drawable-hdpi-v9/noti_logo.png


BIN
Android app/res/drawable-hdpi/action_logo.png


BIN
Android app/res/drawable-hdpi/noti_logo.png


BIN
Android app/res/drawable-mdpi-v11/noti_logo.png


BIN
Android app/res/drawable-mdpi-v9/noti_logo.png


BIN
Android app/res/drawable-mdpi/action_logo.png


BIN
Android app/res/drawable-mdpi/noti_logo.png


BIN
Android app/res/drawable-xhdpi-v11/noti_logo.png


BIN
Android app/res/drawable-xhdpi-v9/noti_logo.png


BIN
Android app/res/drawable-xhdpi/action_logo.png


BIN
Android app/res/drawable-xhdpi/noti_logo.png


BIN
Android app/res/drawable-xxhdpi-v11/noti_logo.png


BIN
Android app/res/drawable-xxhdpi-v9/noti_logo.png


BIN
Android app/res/drawable-xxhdpi/action_logo.png


BIN
Android app/res/drawable-xxhdpi/noti_logo.png


+ 71 - 0
Android app/res/layout/activity_login.xml

@@ -0,0 +1,71 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin"
+    tools:context="com.dev.deben.implementation.LoginActivity">
+
+    <TextView android:text="@string/login" android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:id="@+id/textView" />
+
+    <EditText
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:id="@+id/username"
+        android:inputType="textNoSuggestions"
+        android:layout_marginTop="74dp"
+        android:layout_below="@+id/textView"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true"
+        android:hint="Username" />
+
+    <EditText
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:inputType="textPassword"
+        android:ems="10"
+        android:id="@+id/password"
+        android:layout_below="@+id/username"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true"
+        android:hint="Password" />
+
+    <EditText
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:inputType="number"
+        android:ems="10"
+        android:id="@+id/regCode"
+        android:hint="Register code"
+        android:layout_below="@+id/password"
+        android:layout_alignLeft="@+id/password"
+        android:layout_alignStart="@+id/password" />
+
+    <Button
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="Login"
+        android:id="@+id/login"
+        android:layout_marginTop="95dp"
+        android:layout_below="@+id/regCode"
+        android:layout_alignLeft="@+id/error"
+        android:layout_alignStart="@+id/regCode" />
+
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:id="@+id/error"
+        android:layout_below="@+id/login"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true"
+        android:layout_marginTop="34dp"
+        android:textAlignment="center"
+        android:textColor="#ff0d05"
+        android:textStyle="bold"
+        android:visibility="invisible"
+        android:singleLine="true" />
+
+</RelativeLayout>

+ 54 - 0
Android app/res/layout/activity_main.xml

@@ -0,0 +1,54 @@
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
+    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
+    android:paddingRight="@dimen/activity_horizontal_margin"
+    android:paddingTop="@dimen/activity_vertical_margin"
+    android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity">
+
+    <Button
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="Grand Access"
+        android:id="@+id/Accept"
+        android:background="#04ff00"
+        android:layout_marginBottom="125dp"
+        android:layout_alignParentBottom="true"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentEnd="true"
+        android:capitalize="characters" />
+
+    <Button
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="Deny Access"
+        android:id="@+id/Deny"
+        android:background="#ff1700"
+        android:layout_marginBottom="39dp"
+        android:layout_alignParentBottom="true"
+        android:layout_centerHorizontal="true"
+        android:capitalize="words" />
+
+    <TextView
+        android:layout_width="fill_parent"
+        android:layout_height="wrap_content"
+        android:text="@string/No_req"
+        android:id="@+id/descriptor"
+        android:layout_alignParentTop="true"
+        android:layout_alignParentLeft="true"
+        android:layout_alignParentStart="true"
+        android:layout_marginTop="36dp"
+        android:layout_alignParentRight="true"
+        android:layout_alignParentEnd="true" />
+
+    <TextView
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:textAppearance="?android:attr/textAppearanceSmall"
+        android:text="No action"
+        android:id="@+id/status"
+        android:layout_below="@+id/descriptor"
+        android:layout_centerHorizontal="true"
+        android:layout_marginTop="93dp"
+        android:visibility="invisible" />
+
+</RelativeLayout>

+ 7 - 0
Android app/res/menu/menu_access.xml

@@ -0,0 +1,7 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context="com.dev.deben.implementation.AccessActivity">
+    <item android:id="@+id/action_settings" android:title="@string/action_settings"
+        android:orderInCategory="100" app:showAsAction="never" />
+</menu>

+ 7 - 0
Android app/res/menu/menu_login.xml

@@ -0,0 +1,7 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools"
+    tools:context="com.dev.deben.implementation.LoginActivity">
+    <item android:id="@+id/action_settings" android:title="@string/action_settings"
+        android:orderInCategory="100" app:showAsAction="never" />
+</menu>

+ 6 - 0
Android app/res/menu/menu_main.xml

@@ -0,0 +1,6 @@
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:app="http://schemas.android.com/apk/res-auto"
+    xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity">
+    <item android:id="@+id/action_settings" android:title="@string/action_settings"
+        android:orderInCategory="100" app:showAsAction="never" />
+</menu>

BIN
Android app/res/mipmap-hdpi/ic_launcher.png


BIN
Android app/res/mipmap-hdpi/logo.png


BIN
Android app/res/mipmap-mdpi/ic_launcher.png


BIN
Android app/res/mipmap-mdpi/logo.png


BIN
Android app/res/mipmap-xhdpi/ic_launcher.png


BIN
Android app/res/mipmap-xhdpi/logo.png


BIN
Android app/res/mipmap-xxhdpi/ic_launcher.png


BIN
Android app/res/mipmap-xxhdpi/logo.png


BIN
Android app/res/mipmap-xxxhdpi/logo.png


+ 6 - 0
Android app/res/values-w820dp/dimens.xml

@@ -0,0 +1,6 @@
+<resources>
+    <!-- Example customization of dimensions originally defined in res/values/dimens.xml
+         (such as screen margins) for screens with more than 820dp of available width. This
+         would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). -->
+    <dimen name="activity_horizontal_margin">64dp</dimen>
+</resources>

+ 5 - 0
Android app/res/values/dimens.xml

@@ -0,0 +1,5 @@
+<resources>
+    <!-- Default screen margins, per the Android Design guidelines. -->
+    <dimen name="activity_horizontal_margin">16dp</dimen>
+    <dimen name="activity_vertical_margin">16dp</dimen>
+</resources>

+ 9 - 0
Android app/res/values/strings.xml

@@ -0,0 +1,9 @@
+<resources>
+    <string name="app_name">Access control</string>
+    <string name="action_settings">Settings</string>
+    <string name="title_activity_login">LoginActivity</string>
+    <string name="login">Type here your username and password to register your phone to our VPN service</string>
+    <string name="Main">ONLY grand access if YOU want to login.</string>
+    <string name="No_req">There are currently no pending requests. You will get them when you try to login through VPN</string>
+    <string name="req">There is an active VPN connection request. If it\'s you, you can tab grand access</string>
+</resources>

+ 61 - 0
Android app/res/values/strings_activity_settings.xml

@@ -0,0 +1,61 @@
+<resources>
+    <string name="title_activity_settings">Settings</string>
+
+    <!-- Strings related to Settings -->
+
+    <!-- Example General settings -->
+    <string name="pref_header_general">General</string>
+
+    <string name="pref_title_social_recommendations">Enable social recommendations</string>
+    <string name="pref_description_social_recommendations">Recommendations for people to contact
+        based on your message history
+    </string>
+
+    <string name="pref_title_display_name">Display name</string>
+    <string name="pref_default_display_name">John Smith</string>
+
+    <string name="pref_title_add_friends_to_messages">Add friends to messages</string>
+    <string-array name="pref_example_list_titles">
+        <item>Always</item>
+        <item>When possible</item>
+        <item>Never</item>
+    </string-array>
+    <string-array name="pref_example_list_values">
+        <item>1</item>
+        <item>0</item>
+        <item>-1</item>
+    </string-array>
+
+    <!-- Example settings for Data & Sync -->
+    <string name="pref_header_data_sync">Data &amp; sync</string>
+
+    <string name="pref_title_sync_frequency">Sync frequency</string>
+    <string-array name="pref_sync_frequency_titles">
+        <item>15 minutes</item>
+        <item>30 minutes</item>
+        <item>1 hour</item>
+        <item>3 hours</item>
+        <item>6 hours</item>
+        <item>Never</item>
+    </string-array>
+    <string-array name="pref_sync_frequency_values">
+        <item>15</item>
+        <item>30</item>
+        <item>60</item>
+        <item>180</item>
+        <item>360</item>
+        <item>-1</item>
+    </string-array>
+
+    <string name="pref_title_system_sync_settings">System sync settings</string>
+
+    <!-- Example settings for Notifications -->
+    <string name="pref_header_notifications">Notifications</string>
+
+    <string name="pref_title_new_message_notifications">New message notifications</string>
+
+    <string name="pref_title_ringtone">Ringtone</string>
+    <string name="pref_ringtone_silent">Silent</string>
+
+    <string name="pref_title_vibrate">Vibrate</string>
+</resources>

+ 8 - 0
Android app/res/values/styles.xml

@@ -0,0 +1,8 @@
+<resources>
+
+    <!-- Base application theme. -->
+    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
+        <!-- Customize your theme here. -->
+    </style>
+
+</resources>

+ 21 - 0
Android app/res/xml/pref_data_sync.xml

@@ -0,0 +1,21 @@
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
+         dismiss it. -->
+    <!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
+    <ListPreference
+        android:key="sync_frequency"
+        android:title="@string/pref_title_sync_frequency"
+        android:entries="@array/pref_sync_frequency_titles"
+        android:entryValues="@array/pref_sync_frequency_values"
+        android:defaultValue="180"
+        android:negativeButtonText="@null"
+        android:positiveButtonText="@null" />
+
+    <!-- This preference simply launches an intent when selected. Use this UI sparingly, per
+         design guidelines. -->
+    <Preference android:title="@string/pref_title_system_sync_settings">
+        <intent android:action="android.settings.SYNC_SETTINGS" />
+    </Preference>
+
+</PreferenceScreen>

+ 33 - 0
Android app/res/xml/pref_general.xml

@@ -0,0 +1,33 @@
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <CheckBoxPreference
+        android:key="example_checkbox"
+        android:title="@string/pref_title_social_recommendations"
+        android:summary="@string/pref_description_social_recommendations"
+        android:defaultValue="true" />
+
+    <!-- NOTE: EditTextPreference accepts EditText attributes. -->
+    <!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
+    <EditTextPreference
+        android:key="example_text"
+        android:title="@string/pref_title_display_name"
+        android:defaultValue="@string/pref_default_display_name"
+        android:selectAllOnFocus="true"
+        android:inputType="textCapWords"
+        android:capitalize="words"
+        android:singleLine="true"
+        android:maxLines="1" />
+
+    <!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
+         dismiss it. -->
+    <!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
+    <ListPreference
+        android:key="example_list"
+        android:title="@string/pref_title_add_friends_to_messages"
+        android:defaultValue="-1"
+        android:entries="@array/pref_example_list_titles"
+        android:entryValues="@array/pref_example_list_values"
+        android:negativeButtonText="@null"
+        android:positiveButtonText="@null" />
+
+</PreferenceScreen>

+ 17 - 0
Android app/res/xml/pref_headers.xml

@@ -0,0 +1,17 @@
+<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- These settings headers are only used on tablets. -->
+
+    <header
+        android:fragment="com.dev.deben.implementation.SettingsActivity$GeneralPreferenceFragment"
+        android:title="@string/pref_header_general" />
+
+    <header
+        android:fragment="com.dev.deben.implementation.SettingsActivity$NotificationPreferenceFragment"
+        android:title="@string/pref_header_notifications" />
+
+    <header
+        android:fragment="com.dev.deben.implementation.SettingsActivity$DataSyncPreferenceFragment"
+        android:title="@string/pref_header_data_sync" />
+
+</preference-headers>

+ 27 - 0
Android app/res/xml/pref_notification.xml

@@ -0,0 +1,27 @@
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
+
+    <!-- A 'parent' preference, which enables/disables child preferences (below)
+         when checked/unchecked. -->
+    <CheckBoxPreference
+        android:key="notifications_new_message"
+        android:title="@string/pref_title_new_message_notifications"
+        android:defaultValue="true" />
+
+    <!-- Allows the user to choose a ringtone in the 'notification' category. -->
+    <!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
+    <!-- NOTE: RingtonePreference's summary should be set to its value by the activity code. -->
+    <RingtonePreference
+        android:dependency="notifications_new_message"
+        android:key="notifications_new_message_ringtone"
+        android:title="@string/pref_title_ringtone"
+        android:ringtoneType="notification"
+        android:defaultValue="content://settings/system/notification_sound" />
+
+    <!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
+    <CheckBoxPreference
+        android:dependency="notifications_new_message"
+        android:key="notifications_new_message_vibrate"
+        android:title="@string/pref_title_vibrate"
+        android:defaultValue="true" />
+
+</PreferenceScreen>