Free as in Freedom: Codeberg.org. Create your repos and join us!
Join Donate
Browse Source

First checkin of actual code

Andreas Shimokawa 4 years ago
parent
commit
dada70e92c
32 changed files with 1329 additions and 0 deletions
  1. 3
    0
      .gitignore
  2. 25
    0
      README.md
  3. 26
    0
      app/build.gradle
  4. 17
    0
      app/proguard-rules.pro
  5. 13
    0
      app/src/androidTest/java/nodomain/freeyourgadget/gadgetbridge/ApplicationTest.java
  6. 36
    0
      app/src/main/AndroidManifest.xml
  7. 236
    0
      app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java
  8. 39
    0
      app/src/main/java/nodomain/freeyourgadget/gadgetbridge/NotificationListener.java
  9. 133
    0
      app/src/main/java/nodomain/freeyourgadget/gadgetbridge/PebbleProtocol.java
  10. 258
    0
      app/src/main/java/nodomain/freeyourgadget/gadgetbridge/SettingsActivity.java
  11. BIN
      app/src/main/res/drawable-hdpi/ic_launcher.png
  12. BIN
      app/src/main/res/drawable-mdpi/ic_launcher.png
  13. BIN
      app/src/main/res/drawable-xhdpi/ic_launcher.png
  14. BIN
      app/src/main/res/drawable-xxhdpi/ic_launcher.png
  15. 54
    0
      app/src/main/res/layout/activity_controlcenter.xml
  16. 7
    0
      app/src/main/res/menu/menu_main.xml
  17. 6
    0
      app/src/main/res/values-w820dp/dimens.xml
  18. 5
    0
      app/src/main/res/values/dimens.xml
  19. 9
    0
      app/src/main/res/values/strings.xml
  20. 60
    0
      app/src/main/res/values/strings_activity_settings.xml
  21. 8
    0
      app/src/main/res/values/styles.xml
  22. 21
    0
      app/src/main/res/xml/pref_data_sync.xml
  23. 33
    0
      app/src/main/res/xml/pref_general.xml
  24. 15
    0
      app/src/main/res/xml/pref_headers.xml
  25. 27
    0
      app/src/main/res/xml/pref_notification.xml
  26. 19
    0
      build.gradle
  27. 18
    0
      gradle.properties
  28. BIN
      gradle/wrapper/gradle-wrapper.jar
  29. 6
    0
      gradle/wrapper/gradle-wrapper.properties
  30. 164
    0
      gradlew
  31. 90
    0
      gradlew.bat
  32. 1
    0
      settings.gradle

+ 3
- 0
.gitignore View File

@@ -24,3 +24,6 @@ proguard/
24 24
 
25 25
 # Log Files
26 26
 *.log
27
+
28
+.idea
29
+*.iml

+ 25
- 0
README.md View File

@@ -1,2 +1,27 @@
1 1
 Gadgetbridge
2 2
 ============
3
+
4
+Gadgetbridge is a Android (4.4+) Application which will allow you to use your
5
+Gadget (Smartwatches/Fitness Bands etc) without the vendors closed source
6
+application and without the need to create an account and sync your data to the
7
+vendors servers.
8
+
9
+Right now this is in very early testing stages and only supports the Pebble.
10
+
11
+USE IT AT YOUR OWN RISK. It will problably not work. And if it works it will
12
+annoy you more than it helps you ;)
13
+
14
+Known Visible Issues:
15
+
16
+* No special notifications, EVERYTHING will be send as a Chat/SMS message
17
+* Notifications are not properly queued, if two arrive at about the same time,
18
+  one of them will get lost
19
+* Connection to Pebble will be reopened and closed for every message (dont know
20
+  if this saves or consumes more energy)
21
+* Android 4.4+ only, we can only change this by implementing an
22
+  AccessibiltyService. Don't know if it is worth the hassle.
23
+* This will open the dialog to allow capturing notifications every time the
24
+  Activity gets restarted.
25
+
26
+Apart from that there are many internal design flaws which we will discuss using
27
+the issue tracker.

+ 26
- 0
app/build.gradle View File

@@ -0,0 +1,26 @@
1
+apply plugin: 'com.android.application'
2
+
3
+android {
4
+    compileSdkVersion 21
5
+    buildToolsVersion "21.1.2"
6
+
7
+    defaultConfig {
8
+        applicationId "nodomain.freeyourgadget.gadgetbridge"
9
+        minSdkVersion 19
10
+        targetSdkVersion 21
11
+        versionCode 1
12
+        versionName "1.0"
13
+    }
14
+    buildTypes {
15
+        release {
16
+            minifyEnabled false
17
+            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
18
+        }
19
+    }
20
+}
21
+
22
+dependencies {
23
+    compile fileTree(dir: 'libs', include: ['*.jar'])
24
+    compile 'com.android.support:appcompat-v7:21.0.3'
25
+    compile 'com.android.support:support-v4:21.0.3'
26
+}

+ 17
- 0
app/proguard-rules.pro View File

@@ -0,0 +1,17 @@
1
+# Add project specific ProGuard rules here.
2
+# By default, the flags in this file are appended to flags specified
3
+# in /home/andi/Android/Sdk/tools/proguard/proguard-android.txt
4
+# You can edit the include path and order by changing the proguardFiles
5
+# directive in build.gradle.
6
+#
7
+# For more details, see
8
+#   http://developer.android.com/guide/developing/tools/proguard.html
9
+
10
+# Add any project specific keep options here:
11
+
12
+# If your project uses WebView with JS, uncomment the following
13
+# and specify the fully qualified class name to the JavaScript interface
14
+# class:
15
+#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
16
+#   public *;
17
+#}

+ 13
- 0
app/src/androidTest/java/nodomain/freeyourgadget/gadgetbridge/ApplicationTest.java View File

@@ -0,0 +1,13 @@
1
+package nodomain.freeyourgadget.gadgetbridge;
2
+
3
+import android.app.Application;
4
+import android.test.ApplicationTestCase;
5
+
6
+/**
7
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a>
8
+ */
9
+public class ApplicationTest extends ApplicationTestCase<Application> {
10
+    public ApplicationTest() {
11
+        super(Application.class);
12
+    }
13
+}

+ 36
- 0
app/src/main/AndroidManifest.xml View File

@@ -0,0 +1,36 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3
+    package="nodomain.freeyourgadget.gadgetbridge">
4
+
5
+    <uses-permission android:name="android.permission.BLUETOOTH" />
6
+
7
+    <application
8
+
9
+
10
+        android:allowBackup="true"
11
+        android:icon="@drawable/ic_launcher"
12
+        android:label="@string/app_name"
13
+        android:theme="@style/AppTheme">
14
+        <activity
15
+            android:name="nodomain.freeyourgadget.gadgetbridge.SettingsActivity"
16
+            android:label="@string/app_name"></activity>
17
+        <activity
18
+            android:name="nodomain.freeyourgadget.gadgetbridge.ControlCenter"
19
+            android:label="@string/title_activity_main">
20
+            <intent-filter>
21
+                <action android:name="android.intent.action.MAIN" />
22
+                <category android:name="android.intent.category.LAUNCHER" />
23
+            </intent-filter>
24
+        </activity>
25
+
26
+        <service
27
+            android:name="nodomain.freeyourgadget.gadgetbridge.NotificationListener"
28
+            android:label="@string/app_name"
29
+            android:permission="android.permission.BIND_NOTIFICATION_LISTENER_SERVICE">
30
+            <intent-filter>
31
+                <action android:name="android.service.notification.NotificationListenerService" />
32
+            </intent-filter>
33
+        </service>
34
+    </application>
35
+
36
+</manifest>

+ 236
- 0
app/src/main/java/nodomain/freeyourgadget/gadgetbridge/ControlCenter.java View File

@@ -0,0 +1,236 @@
1
+package nodomain.freeyourgadget.gadgetbridge;
2
+
3
+import android.app.NotificationManager;
4
+import android.bluetooth.BluetoothAdapter;
5
+import android.bluetooth.BluetoothDevice;
6
+import android.bluetooth.BluetoothSocket;
7
+import android.content.BroadcastReceiver;
8
+import android.content.Context;
9
+import android.content.Intent;
10
+import android.content.IntentFilter;
11
+import android.os.AsyncTask;
12
+import android.os.Bundle;
13
+import android.os.SystemClock;
14
+import android.support.v4.app.NotificationCompat;
15
+import android.support.v7.app.ActionBarActivity;
16
+import android.view.Menu;
17
+import android.view.MenuItem;
18
+import android.view.View;
19
+import android.widget.Button;
20
+import android.widget.EditText;
21
+import android.widget.Toast;
22
+
23
+import java.io.IOException;
24
+import java.io.InputStream;
25
+import java.io.OutputStream;
26
+import java.util.Set;
27
+import java.util.UUID;
28
+
29
+public class ControlCenter extends ActionBarActivity {
30
+    // SPP Serial Device UUID
31
+    private static final UUID SERIAL_UUID = UUID.fromString("00001101-0000-1000-8000-00805f9b34fb");
32
+
33
+    BluetoothAdapter mBtAdapter;
34
+    BluetoothDevice mBtDevice;
35
+    BluetoothSocket mBtSocket;
36
+    Button sendButton;
37
+    Button testNotificationButton;
38
+    EditText editTitle;
39
+    EditText editContent;
40
+    private NotificationReceiver nReceiver;
41
+
42
+    @Override
43
+    protected void onCreate(Bundle savedInstanceState) {
44
+        super.onCreate(savedInstanceState);
45
+        setContentView(R.layout.activity_controlcenter);
46
+
47
+        //Check the system status
48
+        mBtAdapter = BluetoothAdapter.getDefaultAdapter();
49
+        if (mBtAdapter == null) {
50
+            Toast.makeText(this, "Bluetooth is not supported.", Toast.LENGTH_SHORT).show();
51
+            finish();
52
+            return;
53
+        }
54
+        if (!mBtAdapter.isEnabled()) {
55
+            Toast.makeText(this, "Bluetooth is disabled.", Toast.LENGTH_SHORT).show();
56
+            finish();
57
+            return;
58
+        }
59
+
60
+        Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
61
+        for (BluetoothDevice device : pairedDevices) {
62
+            if (device.getName().indexOf("Pebble") == 0) {
63
+                // Matching device found
64
+                mBtDevice = device;
65
+            }
66
+        }
67
+
68
+        editTitle = (EditText) findViewById(R.id.editTitle);
69
+        editContent = (EditText) findViewById(R.id.editContent);
70
+        sendButton = (Button) findViewById(R.id.sendButton);
71
+        sendButton.setOnClickListener(new View.OnClickListener() {
72
+            @Override
73
+            public void onClick(View v) {
74
+
75
+                if (!mBtAdapter.isEnabled() || mBtDevice == null)
76
+                    return;
77
+                String title = editTitle.getText().toString();
78
+                String content = editContent.getText().toString();
79
+                try {
80
+                    if (mBtSocket == null || !mBtSocket.isConnected()) {
81
+                        mBtSocket = mBtDevice.createRfcommSocketToServiceRecord(SERIAL_UUID);
82
+                        mBtSocket.connect();
83
+                    }
84
+                    ConnectedTask task = new ConnectedTask();
85
+                    task.execute(mBtSocket, title, content);
86
+                } catch (IOException e) {
87
+                    e.printStackTrace();
88
+                }
89
+            }
90
+        });
91
+        testNotificationButton = (Button) findViewById(R.id.testNotificationButton);
92
+        testNotificationButton.setOnClickListener(new View.OnClickListener() {
93
+            @Override
94
+            public void onClick(View v) {
95
+                testNotification();
96
+            }
97
+        });
98
+
99
+        Intent enableIntent = new Intent("android.settings.ACTION_NOTIFICATION_LISTENER_SETTINGS");
100
+
101
+        startActivity(enableIntent);
102
+        nReceiver = new NotificationReceiver();
103
+
104
+        IntentFilter filter = new IntentFilter();
105
+        filter.addAction("nodomain.freeyourgadget.gadgetbridge.NOTIFICATION_LISTENER");
106
+        registerReceiver(nReceiver, filter);
107
+    }
108
+
109
+    private void testNotification() {
110
+        NotificationManager nManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
111
+        NotificationCompat.Builder ncomp = new NotificationCompat.Builder(this);
112
+        ncomp.setContentTitle("Test Notification");
113
+        ncomp.setContentText("This is a Test Notification from Gadgetbridge");
114
+        ncomp.setTicker("This is a Test Notificytion from Gadgetbridge");
115
+        ncomp.setSmallIcon(R.drawable.ic_launcher);
116
+        ncomp.setAutoCancel(true);
117
+        nManager.notify((int) System.currentTimeMillis(), ncomp.build());
118
+    }
119
+
120
+    @Override
121
+    public boolean onCreateOptionsMenu(Menu menu) {
122
+        // Inflate the menu; this adds items to the action bar if it is present.
123
+        getMenuInflater().inflate(R.menu.menu_main, menu);
124
+        return true;
125
+    }
126
+
127
+    @Override
128
+    public boolean onOptionsItemSelected(MenuItem item) {
129
+        // Handle action bar item clicks here. The action bar will
130
+        // automatically handle clicks on the Home/Up button, so long
131
+        // as you specify a parent activity in AndroidManifest.xml.
132
+        int id = item.getItemId();
133
+
134
+        //noinspection SimplifiableIfStatement
135
+        if (id == R.id.action_settings) {
136
+            //Intent intent = new Intent(this, SettingsActivity.class);
137
+            //startActivity(intent);
138
+            return true;
139
+        }
140
+
141
+        return super.onOptionsItemSelected(item);
142
+    }
143
+
144
+
145
+    @Override
146
+    public void onDestroy() {
147
+        super.onDestroy();
148
+        try {
149
+            if (mBtSocket != null) {
150
+                mBtSocket.close();
151
+            }
152
+        } catch (IOException e) {
153
+            e.printStackTrace();
154
+        }
155
+        if (nReceiver != null) {
156
+            unregisterReceiver(nReceiver);
157
+        }
158
+    }
159
+
160
+
161
+    //AsyncTask to receive a single line of data and post
162
+    private class ConnectedTask extends
163
+            AsyncTask<Object, Void, String> {
164
+        @Override
165
+        protected String doInBackground(
166
+                Object... params) {
167
+            InputStream in = null;
168
+            OutputStream out = null;
169
+            BluetoothSocket socket = (BluetoothSocket) params[0];
170
+            String title = (String) params[1];
171
+            String content = (String) params[2];
172
+            try {
173
+                byte[] buffer = new byte[1024];
174
+                String result;
175
+                in = socket.getInputStream();
176
+
177
+                //in.read(buffer);
178
+                //result = PebbleProtocol.decodeResponse(buffer);
179
+
180
+                out = socket.getOutputStream();
181
+
182
+
183
+                byte[] msg;
184
+                msg = PebbleProtocol.encodeSMS(title, content);
185
+
186
+                //msg = PebbleProtocol.encodeSetTime();
187
+                //msg = PebbleProtocol.encodeIncomingCall("03012323", title);
188
+                //msg = PebbleProtocol.encodeEmail(title, "subject", content);
189
+
190
+                out.write(msg);
191
+                SystemClock.sleep(500);
192
+                //in.read(buffer);
193
+                //result = PebbleProtocol.decodeResponse(buffer);
194
+                result = "ok";
195
+                //Close the connection
196
+                return result.trim();
197
+            } catch (Exception exc) {
198
+                return "error";
199
+            }
200
+        }
201
+
202
+        @Override
203
+        protected void onPostExecute(String result) {
204
+            Toast.makeText(ControlCenter.this, result,
205
+                    Toast.LENGTH_SHORT).show();
206
+            try {
207
+                mBtSocket.close();
208
+            } catch (IOException e) {
209
+                e.printStackTrace();
210
+            }
211
+        }
212
+
213
+    }
214
+
215
+    class NotificationReceiver extends BroadcastReceiver {
216
+        @Override
217
+        public void onReceive(Context context, Intent intent) {
218
+            if (!mBtAdapter.isEnabled() || mBtDevice == null)
219
+                return;
220
+
221
+            String title = intent.getStringExtra("notification_title");
222
+            String content = intent.getStringExtra("notification_content");
223
+            try {
224
+                if (mBtSocket == null || !mBtSocket.isConnected()) {
225
+                    mBtSocket = mBtDevice.createRfcommSocketToServiceRecord(SERIAL_UUID);
226
+                    mBtSocket.connect();
227
+                }
228
+                ConnectedTask task = new ConnectedTask();
229
+                task.execute(mBtSocket, title, content);
230
+            } catch (IOException e) {
231
+                e.printStackTrace();
232
+            }
233
+
234
+        }
235
+    }
236
+}

+ 39
- 0
app/src/main/java/nodomain/freeyourgadget/gadgetbridge/NotificationListener.java View File

@@ -0,0 +1,39 @@
1
+package nodomain.freeyourgadget.gadgetbridge;
2
+
3
+import android.app.Notification;
4
+import android.content.Intent;
5
+import android.os.Bundle;
6
+import android.service.notification.NotificationListenerService;
7
+import android.service.notification.StatusBarNotification;
8
+
9
+public class NotificationListener extends NotificationListenerService {
10
+
11
+    private String TAG = this.getClass().getSimpleName();
12
+
13
+    @Override
14
+    public void onCreate() {
15
+        super.onCreate();
16
+    }
17
+
18
+    @Override
19
+    public void onDestroy() {
20
+        super.onDestroy();
21
+    }
22
+
23
+    @Override
24
+    public void onNotificationPosted(StatusBarNotification sbn) {
25
+        Intent i = new Intent("nodomain.freeyourgadget.gadgetbridge.NOTIFICATION_LISTENER");
26
+        Notification notification = sbn.getNotification();
27
+        Bundle extras = notification.extras;
28
+        String title = extras.getCharSequence(Notification.EXTRA_TITLE).toString();
29
+        String content = extras.getCharSequence(Notification.EXTRA_TEXT).toString();
30
+        i.putExtra("notification_title", title);
31
+        i.putExtra("notification_content", content);
32
+        sendBroadcast(i);
33
+    }
34
+
35
+    @Override
36
+    public void onNotificationRemoved(StatusBarNotification sbn) {
37
+
38
+    }
39
+}

+ 133
- 0
app/src/main/java/nodomain/freeyourgadget/gadgetbridge/PebbleProtocol.java View File

@@ -0,0 +1,133 @@
1
+package nodomain.freeyourgadget.gadgetbridge;
2
+
3
+import java.nio.ByteBuffer;
4
+import java.nio.ByteOrder;
5
+import java.util.SimpleTimeZone;
6
+
7
+public class PebbleProtocol {
8
+    static final short ENDPOINT_FIRMWARE = 1;
9
+    static final short ENDPOINT_TIME = 11;
10
+    static final short ENDPOINT_FIRMWAREVERSION = 16;
11
+    static final short ENDPOINT_PHONEVERSION = 17;
12
+    static final short ENDPOINT_SYSTEMMESSAGE = 18;
13
+    static final short ENDPOINT_MUSICCONTROL = 32;
14
+    static final short ENDPOINT_PHONECONTROL = 33;
15
+    static final short ENDPOINT_APPLICATIONMESSAGE = 48;
16
+    static final short ENDPOINT_LAUNCHER = 49;
17
+    static final short ENDPOINT_LOGS = 2000;
18
+    static final short ENDPOINT_PING = 2001;
19
+    static final short ENDPOINT_LOGDUMP = 2002;
20
+    static final short ENDPOINT_RESET = 2003;
21
+    static final short ENDPOINT_APP = 2004;
22
+    static final short ENDPOINT_APPLOGS = 2006;
23
+    static final short ENDPOINT_NOTIFICATION = 3000;
24
+    static final short ENDPOINT_RESOURCE = 4000;
25
+    static final short ENDPOINT_SYSREG = 5000;
26
+    static final short ENDPOINT_FCTREG = 5001;
27
+    static final short ENDPOINT_APPMANAGER = 6000;
28
+    static final short ENDPOINT_RUNKEEPER = 7000;
29
+    static final short ENDPOINT_SCREENSHOT = 8000;
30
+    static final short ENDPOINT_PUTBYTES = (short) 48879;
31
+
32
+    static final byte NOTIFICATION_EMAIL = 0;
33
+    static final byte NOTIFICATION_SMS = 1;
34
+    static final byte NOTIFICATION_TWITTER = 2;
35
+    static final byte NOTIFICATION_FACEBOOK = 3;
36
+
37
+    static final byte PHONECONTROL_ANSWER = 1;
38
+    static final byte PHONECONTROL_HANGUP = 2;
39
+    static final byte PHONECONTROL_GETSTATE = 3;
40
+    static final byte PHONECONTROL_INCOMINGCALL = 4;
41
+    static final byte PHONECONTROL_OUTGOINGCALL = 5;
42
+    static final byte PHONECONTROL_MISSEDCALL = 6;
43
+    static final byte PHONECONTROL_RING = 7;
44
+    static final byte PHONECONTROL_START = 8;
45
+    static final byte PHONECONTROL_END = 9;
46
+
47
+    static final byte TIME_GETTIME = 0;
48
+    static final byte TIME_SETTIME = 2;
49
+
50
+    static final byte LENGTH_PREFIX = 4;
51
+    static final byte LENGTH_SETTIME = 9;
52
+
53
+    static byte[] encodeMessage(short endpoint, byte type, String[] parts) {
54
+        // Calculate length first
55
+        int length = LENGTH_PREFIX + 1;
56
+        for (String s : parts) {
57
+            length += (1 + s.getBytes().length);
58
+        }
59
+
60
+        // Encode Prefix
61
+        ByteBuffer buf = ByteBuffer.allocate(length);
62
+        buf.order(ByteOrder.BIG_ENDIAN);
63
+        buf.putShort((short) (length - LENGTH_PREFIX));
64
+        buf.putShort(endpoint);
65
+        buf.put(type);
66
+
67
+        // Encode Pascal-Style Strings
68
+        for (String s : parts) {
69
+
70
+            int partlength = s.getBytes().length;
71
+            if (partlength > 255) partlength = 255;
72
+            buf.put((byte) partlength);
73
+            buf.put(s.getBytes(), 0, partlength);
74
+        }
75
+
76
+        return buf.array();
77
+    }
78
+
79
+    public static byte[] encodeSMS(String from, String body) {
80
+        Long ts = System.currentTimeMillis() / 1000;
81
+        String tsstring = ts.toString();  // SIC
82
+        String[] parts = {from, body, tsstring};
83
+
84
+        return encodeMessage(ENDPOINT_NOTIFICATION, NOTIFICATION_SMS, parts);
85
+    }
86
+
87
+    public static byte[] encodeEmail(String from, String subject, String body) {
88
+        Long ts = System.currentTimeMillis() / 1000;
89
+        String tsstring = ts.toString(); // SIC
90
+        String[] parts = {from, body, tsstring, subject};
91
+
92
+        return encodeMessage(ENDPOINT_NOTIFICATION, NOTIFICATION_EMAIL, parts);
93
+    }
94
+
95
+    public static byte[] encodeSetTime() {
96
+        long ts = System.currentTimeMillis() / 1000;
97
+        ts += SimpleTimeZone.getDefault().getOffset(ts) / 1000;
98
+        ByteBuffer buf = ByteBuffer.allocate(LENGTH_SETTIME);
99
+        buf.order(ByteOrder.BIG_ENDIAN);
100
+        buf.putShort((short) (LENGTH_SETTIME - LENGTH_PREFIX));
101
+        buf.putShort(ENDPOINT_TIME);
102
+        buf.put(TIME_SETTIME);
103
+        buf.putInt((int) ts);
104
+
105
+        return buf.array();
106
+    }
107
+
108
+    public static byte[] encodeIncomingCall(String number, String name) {
109
+        String cookie = "000"; // That's a dirty trick to make the cookie part 4 bytes long :P
110
+        String[] parts = {cookie, number, name};
111
+        return encodeMessage(ENDPOINT_PHONECONTROL, PHONECONTROL_INCOMINGCALL, parts);
112
+    }
113
+
114
+    // FIXME: that should return data into some unified struct/Class
115
+    public static String decodeResponse(byte[] responseData) {
116
+        ByteBuffer buf = ByteBuffer.wrap(responseData);
117
+        buf.order(ByteOrder.BIG_ENDIAN);
118
+        short length = buf.getShort();
119
+        short endpoint = buf.getShort();
120
+        byte extra = 0;
121
+
122
+        switch (endpoint) {
123
+            case ENDPOINT_PHONECONTROL:
124
+                extra = buf.get();
125
+                break;
126
+            default:
127
+                break;
128
+        }
129
+        String ret = Short.toString(length) + "/" + Short.toString(endpoint) + "/" + Byte.toString(extra);
130
+
131
+        return ret;
132
+    }
133
+}

+ 258
- 0
app/src/main/java/nodomain/freeyourgadget/gadgetbridge/SettingsActivity.java View File

@@ -0,0 +1,258 @@
1
+package nodomain.freeyourgadget.gadgetbridge;
2
+
3
+import android.annotation.TargetApi;
4
+import android.content.Context;
5
+import android.content.res.Configuration;
6
+import android.media.Ringtone;
7
+import android.media.RingtoneManager;
8
+import android.net.Uri;
9
+import android.os.Build;
10
+import android.os.Bundle;
11
+import android.preference.ListPreference;
12
+import android.preference.Preference;
13
+import android.preference.PreferenceActivity;
14
+import android.preference.PreferenceCategory;
15
+import android.preference.PreferenceFragment;
16
+import android.preference.PreferenceManager;
17
+import android.preference.RingtonePreference;
18
+import android.text.TextUtils;
19
+
20
+import java.util.List;
21
+
22
+/**
23
+ * A {@link PreferenceActivity} that presents a set of application settings. On
24
+ * handset devices, settings are presented as a single list. On tablets,
25
+ * settings are split by category, with category headers shown to the left of
26
+ * the list of settings.
27
+ * <p/>
28
+ * See <a href="http://developer.android.com/design/patterns/settings.html">
29
+ * Android Design: Settings</a> for design guidelines and the <a
30
+ * href="http://developer.android.com/guide/topics/ui/settings.html">Settings
31
+ * API Guide</a> for more information on developing a Settings UI.
32
+ */
33
+public class SettingsActivity extends PreferenceActivity {
34
+    /**
35
+     * Determines whether to always show the simplified settings UI, where
36
+     * settings are presented in a single list. When false, settings are shown
37
+     * as a master/detail two-pane view on tablets. When true, a single pane is
38
+     * shown on tablets.
39
+     */
40
+    private static final boolean ALWAYS_SIMPLE_PREFS = false;
41
+
42
+
43
+    @Override
44
+    protected void onPostCreate(Bundle savedInstanceState) {
45
+        super.onPostCreate(savedInstanceState);
46
+
47
+        setupSimplePreferencesScreen();
48
+    }
49
+
50
+    /**
51
+     * Shows the simplified settings UI if the device configuration if the
52
+     * device configuration dictates that a simplified, single-pane UI should be
53
+     * shown.
54
+     */
55
+    private void setupSimplePreferencesScreen() {
56
+        if (!isSimplePreferences(this)) {
57
+            return;
58
+        }
59
+
60
+        // In the simplified UI, fragments are not used at all and we instead
61
+        // use the older PreferenceActivity APIs.
62
+
63
+        // Add 'general' preferences.
64
+        addPreferencesFromResource(R.xml.pref_general);
65
+
66
+        // Add 'notifications' preferences, and a corresponding header.
67
+        PreferenceCategory fakeHeader = new PreferenceCategory(this);
68
+        fakeHeader.setTitle(R.string.pref_header_notifications);
69
+        getPreferenceScreen().addPreference(fakeHeader);
70
+        addPreferencesFromResource(R.xml.pref_notification);
71
+
72
+        // Add 'data and sync' preferences, and a corresponding header.
73
+        fakeHeader = new PreferenceCategory(this);
74
+        fakeHeader.setTitle(R.string.pref_header_data_sync);
75
+        getPreferenceScreen().addPreference(fakeHeader);
76
+        addPreferencesFromResource(R.xml.pref_data_sync);
77
+
78
+        // Bind the summaries of EditText/List/Dialog/Ringtone preferences to
79
+        // their values. When their values change, their summaries are updated
80
+        // to reflect the new value, per the Android Design guidelines.
81
+        bindPreferenceSummaryToValue(findPreference("example_text"));
82
+        bindPreferenceSummaryToValue(findPreference("example_list"));
83
+        bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
84
+        bindPreferenceSummaryToValue(findPreference("sync_frequency"));
85
+    }
86
+
87
+    /**
88
+     * {@inheritDoc}
89
+     */
90
+    @Override
91
+    public boolean onIsMultiPane() {
92
+        return isXLargeTablet(this) && !isSimplePreferences(this);
93
+    }
94
+
95
+    /**
96
+     * Helper method to determine if the device has an extra-large screen. For
97
+     * example, 10" tablets are extra-large.
98
+     */
99
+    private static boolean isXLargeTablet(Context context) {
100
+        return (context.getResources().getConfiguration().screenLayout
101
+                & Configuration.SCREENLAYOUT_SIZE_MASK) >= Configuration.SCREENLAYOUT_SIZE_XLARGE;
102
+    }
103
+
104
+    /**
105
+     * Determines whether the simplified settings UI should be shown. This is
106
+     * true if this is forced via {@link #ALWAYS_SIMPLE_PREFS}, or the device
107
+     * doesn't have newer APIs like {@link PreferenceFragment}, or the device
108
+     * doesn't have an extra-large screen. In these cases, a single-pane
109
+     * "simplified" settings UI should be shown.
110
+     */
111
+    private static boolean isSimplePreferences(Context context) {
112
+        return ALWAYS_SIMPLE_PREFS
113
+                || Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB
114
+                || !isXLargeTablet(context);
115
+    }
116
+
117
+    /**
118
+     * {@inheritDoc}
119
+     */
120
+    @Override
121
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
122
+    public void onBuildHeaders(List<Header> target) {
123
+        if (!isSimplePreferences(this)) {
124
+            loadHeadersFromResource(R.xml.pref_headers, target);
125
+        }
126
+    }
127
+
128
+    /**
129
+     * A preference value change listener that updates the preference's summary
130
+     * to reflect its new value.
131
+     */
132
+    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
133
+        @Override
134
+        public boolean onPreferenceChange(Preference preference, Object value) {
135
+            String stringValue = value.toString();
136
+
137
+            if (preference instanceof ListPreference) {
138
+                // For list preferences, look up the correct display value in
139
+                // the preference's 'entries' list.
140
+                ListPreference listPreference = (ListPreference) preference;
141
+                int index = listPreference.findIndexOfValue(stringValue);
142
+
143
+                // Set the summary to reflect the new value.
144
+                preference.setSummary(
145
+                        index >= 0
146
+                                ? listPreference.getEntries()[index]
147
+                                : null);
148
+
149
+            } else if (preference instanceof RingtonePreference) {
150
+                // For ringtone preferences, look up the correct display value
151
+                // using RingtoneManager.
152
+                if (TextUtils.isEmpty(stringValue)) {
153
+                    // Empty values correspond to 'silent' (no ringtone).
154
+                    preference.setSummary(R.string.pref_ringtone_silent);
155
+
156
+                } else {
157
+                    Ringtone ringtone = RingtoneManager.getRingtone(
158
+                            preference.getContext(), Uri.parse(stringValue));
159
+
160
+                    if (ringtone == null) {
161
+                        // Clear the summary if there was a lookup error.
162
+                        preference.setSummary(null);
163
+                    } else {
164
+                        // Set the summary to reflect the new ringtone display
165
+                        // name.
166
+                        String name = ringtone.getTitle(preference.getContext());
167
+                        preference.setSummary(name);
168
+                    }
169
+                }
170
+
171
+            } else {
172
+                // For all other preferences, set the summary to the value's
173
+                // simple string representation.
174
+                preference.setSummary(stringValue);
175
+            }
176
+            return true;
177
+        }
178
+    };
179
+
180
+    /**
181
+     * Binds a preference's summary to its value. More specifically, when the
182
+     * preference's value is changed, its summary (line of text below the
183
+     * preference title) is updated to reflect the value. The summary is also
184
+     * immediately updated upon calling this method. The exact display format is
185
+     * dependent on the type of preference.
186
+     *
187
+     * @see #sBindPreferenceSummaryToValueListener
188
+     */
189
+    private static void bindPreferenceSummaryToValue(Preference preference) {
190
+        // Set the listener to watch for value changes.
191
+        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
192
+
193
+        // Trigger the listener immediately with the preference's
194
+        // current value.
195
+        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
196
+                PreferenceManager
197
+                        .getDefaultSharedPreferences(preference.getContext())
198
+                        .getString(preference.getKey(), ""));
199
+    }
200
+
201
+    /**
202
+     * This fragment shows general preferences only. It is used when the
203
+     * activity is showing a two-pane settings UI.
204
+     */
205
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
206
+    public static class GeneralPreferenceFragment extends PreferenceFragment {
207
+        @Override
208
+        public void onCreate(Bundle savedInstanceState) {
209
+            super.onCreate(savedInstanceState);
210
+            addPreferencesFromResource(R.xml.pref_general);
211
+
212
+            // Bind the summaries of EditText/List/Dialog/Ringtone preferences
213
+            // to their values. When their values change, their summaries are
214
+            // updated to reflect the new value, per the Android Design
215
+            // guidelines.
216
+            bindPreferenceSummaryToValue(findPreference("example_text"));
217
+            bindPreferenceSummaryToValue(findPreference("example_list"));
218
+        }
219
+    }
220
+
221
+    /**
222
+     * This fragment shows notification preferences only. It is used when the
223
+     * activity is showing a two-pane settings UI.
224
+     */
225
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
226
+    public static class NotificationPreferenceFragment extends PreferenceFragment {
227
+        @Override
228
+        public void onCreate(Bundle savedInstanceState) {
229
+            super.onCreate(savedInstanceState);
230
+            addPreferencesFromResource(R.xml.pref_notification);
231
+
232
+            // Bind the summaries of EditText/List/Dialog/Ringtone preferences
233
+            // to their values. When their values change, their summaries are
234
+            // updated to reflect the new value, per the Android Design
235
+            // guidelines.
236
+            bindPreferenceSummaryToValue(findPreference("notifications_new_message_ringtone"));
237
+        }
238
+    }
239
+
240
+    /**
241
+     * This fragment shows data and sync preferences only. It is used when the
242
+     * activity is showing a two-pane settings UI.
243
+     */
244
+    @TargetApi(Build.VERSION_CODES.HONEYCOMB)
245
+    public static class DataSyncPreferenceFragment extends PreferenceFragment {
246
+        @Override
247
+        public void onCreate(Bundle savedInstanceState) {
248
+            super.onCreate(savedInstanceState);
249
+            addPreferencesFromResource(R.xml.pref_data_sync);
250
+
251
+            // Bind the summaries of EditText/List/Dialog/Ringtone preferences
252
+            // to their values. When their values change, their summaries are
253
+            // updated to reflect the new value, per the Android Design
254
+            // guidelines.
255
+            bindPreferenceSummaryToValue(findPreference("sync_frequency"));
256
+        }
257
+    }
258
+}

BIN
app/src/main/res/drawable-hdpi/ic_launcher.png View File


BIN
app/src/main/res/drawable-mdpi/ic_launcher.png View File


BIN
app/src/main/res/drawable-xhdpi/ic_launcher.png View File


BIN
app/src/main/res/drawable-xxhdpi/ic_launcher.png View File


+ 54
- 0
app/src/main/res/layout/activity_controlcenter.xml View File

@@ -0,0 +1,54 @@
1
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
2
+    xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
3
+    android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin"
4
+    android:paddingRight="@dimen/activity_horizontal_margin"
5
+    android:paddingTop="@dimen/activity_vertical_margin"
6
+    android:paddingBottom="@dimen/activity_vertical_margin"
7
+    tools:context="nodomain.freeyourgadget.gadgetbridge.ControlCenter">
8
+
9
+    <TextView
10
+        android:id="@+id/label"
11
+        android:layout_width="wrap_content"
12
+        android:layout_height="wrap_content"
13
+        android:textAppearance="?android:attr/textAppearanceLarge"
14
+        android:text="From:" />
15
+    <EditText
16
+        android:id="@+id/editTitle"
17
+        android:layout_width="match_parent"
18
+        android:layout_height="wrap_content"
19
+        android:layout_below="@id/label"
20
+        android:singleLine="true"
21
+        android:inputType="textEmailAddress" />
22
+    <TextView
23
+        android:id="@+id/textView"
24
+        android:layout_width="wrap_content"
25
+        android:layout_height="wrap_content"
26
+        android:textAppearance="?android:attr/textAppearanceLarge"
27
+        android:layout_below="@+id/editTitle"
28
+        android:text="Message"/>
29
+    <EditText
30
+        android:layout_width="wrap_content"
31
+        android:layout_height="wrap_content"
32
+        android:inputType="textMultiLine"
33
+        android:ems="10"
34
+        android:id="@+id/editContent"
35
+        android:layout_alignParentLeft="true"
36
+        android:layout_alignParentStart="true"
37
+        android:layout_alignRight="@+id/editTitle"
38
+        android:layout_alignEnd="@+id/editTitle"
39
+        android:layout_below="@+id/textView" />
40
+    <Button
41
+        android:id="@+id/sendButton"
42
+        android:layout_width="match_parent"
43
+        android:layout_height="wrap_content"
44
+        android:text="Send to Pebble"
45
+        android:layout_above="@+id/testNotificationButton"
46
+        android:layout_alignParentStart="true" />
47
+    <Button
48
+        android:id="@+id/testNotificationButton"
49
+        android:layout_width="match_parent"
50
+        android:layout_height="wrap_content"
51
+        android:text="Create test Notification"
52
+        android:layout_alignParentBottom="true"
53
+        android:layout_alignParentStart="true" />
54
+</RelativeLayout>

+ 7
- 0
app/src/main/res/menu/menu_main.xml View File

@@ -0,0 +1,7 @@
1
+<menu xmlns:android="http://schemas.android.com/apk/res/android"
2
+    xmlns:app="http://schemas.android.com/apk/res-auto"
3
+    xmlns:tools="http://schemas.android.com/tools"
4
+    tools:context="nodomain.freeyourgadget.gadgetbridge.ControlCenter">
5
+    <item android:id="@+id/action_settings" android:title="@string/action_settings"
6
+        android:orderInCategory="100" app:showAsAction="never" />
7
+</menu>

+ 6
- 0
app/src/main/res/values-w820dp/dimens.xml View File

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

+ 5
- 0
app/src/main/res/values/dimens.xml View File

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

+ 9
- 0
app/src/main/res/values/strings.xml View File

@@ -0,0 +1,9 @@
1
+<?xml version="1.0" encoding="utf-8"?>
2
+<resources>
3
+
4
+    <string name="app_name">Gadgetbridge</string>
5
+    <string name="title_activity_main">Gadgetbridge Control Center</string>
6
+    <string name="hello_world">Hello world!</string>
7
+    <string name="action_settings">Settings</string>
8
+
9
+</resources>

+ 60
- 0
app/src/main/res/values/strings_activity_settings.xml View File

@@ -0,0 +1,60 @@
1
+<resources>
2
+
3
+    <!-- Strings related to Settings -->
4
+
5
+    <!-- Example General settings -->
6
+    <string name="pref_header_general">General</string>
7
+
8
+    <string name="pref_title_social_recommendations">Enable social recommendations</string>
9
+    <string name="pref_description_social_recommendations">Recommendations for people to contact
10
+        based on your message history
11
+    </string>
12
+
13
+    <string name="pref_title_display_name">Display name</string>
14
+    <string name="pref_default_display_name">John Smith</string>
15
+
16
+    <string name="pref_title_add_friends_to_messages">Add friends to messages</string>
17
+    <string-array name="pref_example_list_titles">
18
+        <item>Always</item>
19
+        <item>When possible</item>
20
+        <item>Never</item>
21
+    </string-array>
22
+    <string-array name="pref_example_list_values">
23
+        <item>1</item>
24
+        <item>0</item>
25
+        <item>-1</item>
26
+    </string-array>
27
+
28
+    <!-- Example settings for Data & Sync -->
29
+    <string name="pref_header_data_sync">Data &amp; sync</string>
30
+
31
+    <string name="pref_title_sync_frequency">Sync frequency</string>
32
+    <string-array name="pref_sync_frequency_titles">
33
+        <item>15 minutes</item>
34
+        <item>30 minutes</item>
35
+        <item>1 hour</item>
36
+        <item>3 hours</item>
37
+        <item>6 hours</item>
38
+        <item>Never</item>
39
+    </string-array>
40
+    <string-array name="pref_sync_frequency_values">
41
+        <item>15</item>
42
+        <item>30</item>
43
+        <item>60</item>
44
+        <item>180</item>
45
+        <item>360</item>
46
+        <item>-1</item>
47
+    </string-array>
48
+
49
+    <string name="pref_title_system_sync_settings">System sync settings</string>
50
+
51
+    <!-- Example settings for Notifications -->
52
+    <string name="pref_header_notifications">Notifications</string>
53
+
54
+    <string name="pref_title_new_message_notifications">New message notifications</string>
55
+
56
+    <string name="pref_title_ringtone">Ringtone</string>
57
+    <string name="pref_ringtone_silent">Silent</string>
58
+
59
+    <string name="pref_title_vibrate">Vibrate</string>
60
+</resources>

+ 8
- 0
app/src/main/res/values/styles.xml View File

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

+ 21
- 0
app/src/main/res/xml/pref_data_sync.xml View File

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

+ 33
- 0
app/src/main/res/xml/pref_general.xml View File

@@ -0,0 +1,33 @@
1
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
2
+
3
+    <CheckBoxPreference
4
+        android:key="example_checkbox"
5
+        android:title="@string/pref_title_social_recommendations"
6
+        android:summary="@string/pref_description_social_recommendations"
7
+        android:defaultValue="true" />
8
+
9
+    <!-- NOTE: EditTextPreference accepts EditText attributes. -->
10
+    <!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
11
+    <EditTextPreference
12
+        android:key="example_text"
13
+        android:title="@string/pref_title_display_name"
14
+        android:defaultValue="@string/pref_default_display_name"
15
+        android:selectAllOnFocus="true"
16
+        android:inputType="textCapWords"
17
+        android:capitalize="words"
18
+        android:singleLine="true"
19
+        android:maxLines="1" />
20
+
21
+    <!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog to
22
+         dismiss it. -->
23
+    <!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
24
+    <ListPreference
25
+        android:key="example_list"
26
+        android:title="@string/pref_title_add_friends_to_messages"
27
+        android:defaultValue="-1"
28
+        android:entries="@array/pref_example_list_titles"
29
+        android:entryValues="@array/pref_example_list_values"
30
+        android:negativeButtonText="@null"
31
+        android:positiveButtonText="@null" />
32
+
33
+</PreferenceScreen>

+ 15
- 0
app/src/main/res/xml/pref_headers.xml View File

@@ -0,0 +1,15 @@
1
+<preference-headers xmlns:android="http://schemas.android.com/apk/res/android">
2
+
3
+    <!-- These settings headers are only used on tablets. -->
4
+
5
+    <header android:fragment="nodomain.freeyourgadget.gadgetbridge.SettingsActivity$GeneralPreferenceFragment"
6
+        android:title="@string/pref_header_general" />
7
+
8
+    <header
9
+        android:fragment="nodomain.freeyourgadget.gadgetbridge.SettingsActivity$NotificationPreferenceFragment"
10
+        android:title="@string/pref_header_notifications" />
11
+
12
+    <header android:fragment="nodomain.freeyourgadget.gadgetbridge.SettingsActivity$DataSyncPreferenceFragment"
13
+        android:title="@string/pref_header_data_sync" />
14
+
15
+</preference-headers>

+ 27
- 0
app/src/main/res/xml/pref_notification.xml View File

@@ -0,0 +1,27 @@
1
+<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
2
+
3
+    <!-- A 'parent' preference, which enables/disables child preferences (below)
4
+         when checked/unchecked. -->
5
+    <CheckBoxPreference
6
+        android:key="notifications_new_message"
7
+        android:title="@string/pref_title_new_message_notifications"
8
+        android:defaultValue="true" />
9
+
10
+    <!-- Allows the user to choose a ringtone in the 'notification' category. -->
11
+    <!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
12
+    <!-- NOTE: RingtonePreference's summary should be set to its value by the activity code. -->
13
+    <RingtonePreference
14
+        android:dependency="notifications_new_message"
15
+        android:key="notifications_new_message_ringtone"
16
+        android:title="@string/pref_title_ringtone"
17
+        android:ringtoneType="notification"
18
+        android:defaultValue="content://settings/system/notification_sound" />
19
+
20
+    <!-- NOTE: This preference will be enabled only when the checkbox above is checked. -->
21
+    <CheckBoxPreference
22
+        android:dependency="notifications_new_message"
23
+        android:key="notifications_new_message_vibrate"
24
+        android:title="@string/pref_title_vibrate"
25
+        android:defaultValue="true" />
26
+
27
+</PreferenceScreen>

+ 19
- 0
build.gradle View File

@@ -0,0 +1,19 @@
1
+// Top-level build file where you can add configuration options common to all sub-projects/modules.
2
+
3
+buildscript {
4
+    repositories {
5
+        jcenter()
6
+    }
7
+    dependencies {
8
+        classpath 'com.android.tools.build:gradle:1.0.0'
9
+
10
+        // NOTE: Do not place your application dependencies here; they belong
11
+        // in the individual module build.gradle files
12
+    }
13
+}
14
+
15
+allprojects {
16
+    repositories {
17
+        jcenter()
18
+    }
19
+}

+ 18
- 0
gradle.properties View File

@@ -0,0 +1,18 @@
1
+# Project-wide Gradle settings.
2
+
3
+# IDE (e.g. Android Studio) users:
4
+# Gradle settings configured through the IDE *will override*
5
+# any settings specified in this file.
6
+
7
+# For more details on how to configure your build environment visit
8
+# http://www.gradle.org/docs/current/userguide/build_environment.html
9
+
10
+# Specifies the JVM arguments used for the daemon process.
11
+# The setting is particularly useful for tweaking memory settings.
12
+# Default value: -Xmx10248m -XX:MaxPermSize=256m
13
+# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
14
+
15
+# When configured, Gradle will run in incubating parallel mode.
16
+# This option should only be used with decoupled projects. More details, visit
17
+# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
18
+# org.gradle.parallel=true

BIN
gradle/wrapper/gradle-wrapper.jar View File


+ 6
- 0
gradle/wrapper/gradle-wrapper.properties View File

@@ -0,0 +1,6 @@
1
+#Wed Apr 10 15:27:10 PDT 2013
2
+distributionBase=GRADLE_USER_HOME
3
+distributionPath=wrapper/dists
4
+zipStoreBase=GRADLE_USER_HOME
5
+zipStorePath=wrapper/dists
6
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.2.1-all.zip

+ 164
- 0
gradlew View File

@@ -0,0 +1,164 @@
1
+#!/usr/bin/env bash
2
+
3
+##############################################################################
4
+##
5
+##  Gradle start up script for UN*X
6
+##
7
+##############################################################################
8
+
9
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
10
+DEFAULT_JVM_OPTS=""
11
+
12
+APP_NAME="Gradle"
13
+APP_BASE_NAME=`basename "$0"`
14
+
15
+# Use the maximum available, or set MAX_FD != -1 to use that value.
16
+MAX_FD="maximum"
17
+
18
+warn ( ) {
19
+    echo "$*"
20
+}
21
+
22
+die ( ) {
23
+    echo
24
+    echo "$*"
25
+    echo
26
+    exit 1
27
+}
28
+
29
+# OS specific support (must be 'true' or 'false').
30
+cygwin=false
31
+msys=false
32
+darwin=false
33
+case "`uname`" in
34
+  CYGWIN* )
35
+    cygwin=true
36
+    ;;
37
+  Darwin* )
38
+    darwin=true
39
+    ;;
40
+  MINGW* )
41
+    msys=true
42
+    ;;
43
+esac
44
+
45
+# For Cygwin, ensure paths are in UNIX format before anything is touched.
46
+if $cygwin ; then
47
+    [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"`
48
+fi
49
+
50
+# Attempt to set APP_HOME
51
+# Resolve links: $0 may be a link
52
+PRG="$0"
53
+# Need this for relative symlinks.
54
+while [ -h "$PRG" ] ; do
55
+    ls=`ls -ld "$PRG"`
56
+    link=`expr "$ls" : '.*-> \(.*\)$'`
57
+    if expr "$link" : '/.*' > /dev/null; then
58
+        PRG="$link"
59
+    else
60
+        PRG=`dirname "$PRG"`"/$link"
61
+    fi
62
+done
63
+SAVED="`pwd`"
64
+cd "`dirname \"$PRG\"`/" >&-
65
+APP_HOME="`pwd -P`"
66
+cd "$SAVED" >&-
67
+
68
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
69
+
70
+# Determine the Java command to use to start the JVM.
71
+if [ -n "$JAVA_HOME" ] ; then
72
+    if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
73
+        # IBM's JDK on AIX uses strange locations for the executables
74
+        JAVACMD="$JAVA_HOME/jre/sh/java"
75
+    else
76
+        JAVACMD="$JAVA_HOME/bin/java"
77
+    fi
78
+    if [ ! -x "$JAVACMD" ] ; then
79
+        die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
80
+
81
+Please set the JAVA_HOME variable in your environment to match the
82
+location of your Java installation."
83
+    fi
84
+else
85
+    JAVACMD="java"
86
+    which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
87
+
88
+Please set the JAVA_HOME variable in your environment to match the
89
+location of your Java installation."
90
+fi
91
+
92
+# Increase the maximum file descriptors if we can.
93
+if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
94
+    MAX_FD_LIMIT=`ulimit -H -n`
95
+    if [ $? -eq 0 ] ; then
96
+        if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
97
+            MAX_FD="$MAX_FD_LIMIT"
98
+        fi
99
+        ulimit -n $MAX_FD
100
+        if [ $? -ne 0 ] ; then
101
+            warn "Could not set maximum file descriptor limit: $MAX_FD"
102
+        fi
103
+    else
104
+        warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
105
+    fi
106
+fi
107
+
108
+# For Darwin, add options to specify how the application appears in the dock
109
+if $darwin; then
110
+    GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
111
+fi
112
+
113
+# For Cygwin, switch paths to Windows format before running java
114
+if $cygwin ; then
115
+    APP_HOME=`cygpath --path --mixed "$APP_HOME"`
116
+    CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
117
+
118
+    # We build the pattern for arguments to be converted via cygpath
119
+    ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120
+    SEP=""
121
+    for dir in $ROOTDIRSRAW ; do
122
+        ROOTDIRS="$ROOTDIRS$SEP$dir"
123
+        SEP="|"
124
+    done
125
+    OURCYGPATTERN="(^($ROOTDIRS))"
126
+    # Add a user-defined pattern to the cygpath arguments
127
+    if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128
+        OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129
+    fi
130
+    # Now convert the arguments - kludge to limit ourselves to /bin/sh
131
+    i=0
132
+    for arg in "$@" ; do
133
+        CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134
+        CHECK2=`echo "$arg"|egrep -c "^-"`                                 ### Determine if an option
135
+
136
+        if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then                    ### Added a condition
137
+            eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138
+        else
139
+            eval `echo args$i`="\"$arg\""
140
+        fi
141
+        i=$((i+1))
142
+    done
143
+    case $i in
144
+        (0) set -- ;;
145
+        (1) set -- "$args0" ;;
146
+        (2) set -- "$args0" "$args1" ;;
147
+        (3) set -- "$args0" "$args1" "$args2" ;;
148
+        (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149
+        (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150
+        (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151
+        (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152
+        (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153
+        (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154
+    esac
155
+fi
156
+
157
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
158
+function splitJvmOpts() {
159
+    JVM_OPTS=("$@")
160
+}
161
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
162
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
163
+
164
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

+ 90
- 0
gradlew.bat View File

@@ -0,0 +1,90 @@
1
+@if "%DEBUG%" == "" @echo off
2
+@rem ##########################################################################
3
+@rem
4
+@rem  Gradle startup script for Windows
5
+@rem
6
+@rem ##########################################################################
7
+
8
+@rem Set local scope for the variables with windows NT shell
9
+if "%OS%"=="Windows_NT" setlocal
10
+
11
+@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
12
+set DEFAULT_JVM_OPTS=
13
+
14
+set DIRNAME=%~dp0
15
+if "%DIRNAME%" == "" set DIRNAME=.
16
+set APP_BASE_NAME=%~n0
17
+set APP_HOME=%DIRNAME%
18
+
19
+@rem Find java.exe
20
+if defined JAVA_HOME goto findJavaFromJavaHome
21
+
22
+set JAVA_EXE=java.exe
23
+%JAVA_EXE% -version >NUL 2>&1
24
+if "%ERRORLEVEL%" == "0" goto init
25
+
26
+echo.
27
+echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28
+echo.
29
+echo Please set the JAVA_HOME variable in your environment to match the
30
+echo location of your Java installation.
31
+
32
+goto fail
33
+
34
+:findJavaFromJavaHome
35
+set JAVA_HOME=%JAVA_HOME:"=%
36
+set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37
+
38
+if exist "%JAVA_EXE%" goto init
39
+
40
+echo.
41
+echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42
+echo.
43
+echo Please set the JAVA_HOME variable in your environment to match the
44
+echo location of your Java installation.
45
+
46
+goto fail
47
+
48
+:init
49
+@rem Get command-line arguments, handling Windowz variants
50
+
51
+if not "%OS%" == "Windows_NT" goto win9xME_args
52
+if "%@eval[2+2]" == "4" goto 4NT_args
53
+
54
+:win9xME_args
55
+@rem Slurp the command line arguments.
56
+set CMD_LINE_ARGS=
57
+set _SKIP=2
58
+
59
+:win9xME_args_slurp
60
+if "x%~1" == "x" goto execute
61
+
62
+set CMD_LINE_ARGS=%*
63
+goto execute
64
+
65
+:4NT_args
66
+@rem Get arguments from the 4NT Shell from JP Software
67
+set CMD_LINE_ARGS=%$
68
+
69
+:execute
70
+@rem Setup the command line
71
+
72
+set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
73
+
74
+@rem Execute Gradle
75
+"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
76
+
77
+:end
78
+@rem End local scope for the variables with windows NT shell
79
+if "%ERRORLEVEL%"=="0" goto mainEnd
80
+
81
+:fail
82
+rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
83
+rem the _cmd.exe /c_ return code!
84
+if  not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
85
+exit /b 1
86
+
87
+:mainEnd
88
+if "%OS%"=="Windows_NT" endlocal
89
+
90
+:omega

+ 1
- 0
settings.gradle View File

@@ -0,0 +1 @@
1
+include ':app'

Loading…
Cancel
Save