Skip to content
This repository was archived by the owner on Nov 24, 2023. It is now read-only.

Commit 9205e82

Browse files
authored
Merge pull request #67 from kolserdav/develop
Develop
2 parents 1b96c91 + e8480fb commit 9205e82

93 files changed

Lines changed: 1263 additions & 230 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

android/app/build.gradle

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ android {
1010
applicationId "com.kolserdav.ana"
1111
minSdk 21
1212
targetSdk 33
13-
versionCode 132
14-
versionName "1.32"
13+
versionCode 133
14+
versionName "1.33"
1515

1616
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
1717
}
@@ -33,6 +33,7 @@ dependencies {
3333

3434
implementation 'com.google.android.material:material:1.8.0'
3535
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
36+
implementation 'org.java-websocket:Java-WebSocket:1.5.3'
3637
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
3738
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
3839
}

android/app/src/main/AndroidManifest.xml

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
88
<uses-permission android:name="android.permission.RECORD_AUDIO" />
99
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS" />
10+
<uses-permission android:name="android:permission=BIND_JOB_SERVICE" />
11+
1012

1113
<queries>
1214
<intent>
@@ -27,13 +29,18 @@
2729
tools:targetApi="31">
2830
<activity
2931
android:name=".MainActivity"
30-
android:exported="true">
31-
<intent-filter>
32-
<data android:scheme="com.kolserdav.ana"/>
32+
android:exported="true"
33+
android:launchMode="singleTask"
34+
>
35+
<intent-filter android:label="@string/app_name">
3336
<action android:name="android.intent.action.VIEW" />
34-
<category android:name="android.intent.category.LAUNCHER" />
3537
<category android:name="android.intent.category.DEFAULT" />
3638
<category android:name="android.intent.category.BROWSABLE"/>
39+
<!--
40+
android:host has dependency with packages/app/utils/constants.ts.DEEP_LINK_HOST
41+
android:scheme has dependency with packages/app/utils/constants.ts.ANDROID_APP_NAME
42+
-->
43+
<data android:scheme="com.kolserdav.ana" android:host="path"/>
3744
</intent-filter>
3845
<intent-filter>
3946
<action android:name="android.intent.action.MAIN" />
@@ -45,6 +52,10 @@
4552
<data android:mimeType="text/plain" />
4653
</intent-filter>
4754
</activity>
55+
<service
56+
android:name=".DisplayNotification"
57+
android:exported="false"/>
58+
4859
</application>
4960

5061
</manifest>

android/app/src/main/java/com/kolserdav/ana/Config.java

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,12 @@ class AppInterface {
55
String url = null;
66
String path = "/";
77
String urlDefault = "https://uyem.ru";
8-
9-
public AppInterface(int _id, String _url, String _urlDefault, String _path) {
10-
id = _id;
11-
url = _url;
12-
urlDefault = _urlDefault;
13-
path = _path;
14-
}
8+
// Push notifications server
9+
String wsAddress = null;
1510

1611
public AppInterface() {
1712

1813
}
19-
2014
}
2115

2216
public class Config {
@@ -26,11 +20,19 @@ public class Config {
2620
// Dependency packages/app/types/interfaces.ts.CHECK_URL_PATH
2721
public static final String CHECK_URL_PATH = "/api/check";
2822

29-
public static final Integer DATABASE_VERSION = 18;
23+
public static final Integer DATABASE_VERSION = 22;
3024

3125
public static final String DATABASE_NAME = "db";
3226

3327
// Dependency PROCESS_TEXT_QUERY_STRING in packages/app/utils/constants.ts
3428
public static final String QUERY_STRING_PROCESS_TEXT = "process_text";
29+
30+
public static final String CHANNEL_ID = "1";
31+
32+
// Dependency packages/server/src/utils/constants.ts.WS_MESSAGE_NOTIFICATION_USER_ID
33+
public static final String WS_MESSAGE_NOTIFICATION_USER_ID = "notification_user_id";
34+
35+
public static final int WS_RECONNECT_TIMEOUT = 3000;
36+
3537
}
3638

android/app/src/main/java/com/kolserdav/ana/DB.java

Lines changed: 30 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -35,22 +35,25 @@ class App extends Table {
3535
public static final String APP_COLUMN_URL_DEFAULT = "urlDefault";
3636
public static final String APP_COLUMN_PATH = "path";
3737

38+
public static final String APP_COLUMN_WS_ADDRESS = "wsAddress";
39+
3840
private static final String TAG = "App";
3941

4042
public App(SQLiteDatabase db) {
4143
super(db, new String[]{
4244
APP_COLUMN_ID,
4345
APP_COLUMN_URL,
4446
APP_COLUMN_URL_DEFAULT,
45-
APP_COLUMN_PATH
47+
APP_COLUMN_PATH,
48+
APP_COLUMN_WS_ADDRESS
4649
});
4750
}
4851

4952
public void onCreate() {
5053
db.execSQL("CREATE TABLE IF NOT EXISTS " + TABLE_NAME + " (" +
5154
APP_COLUMN_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
5255
APP_COLUMN_URL + " TEXT, " + APP_COLUMN_URL_DEFAULT + " TEXT, " +
53-
APP_COLUMN_PATH + " TEXT" + ")");
56+
APP_COLUMN_PATH + " TEXT, " + APP_COLUMN_WS_ADDRESS + " TEXT" + ")");
5457
}
5558

5659
public void setUrl(AppInterface options) {
@@ -78,9 +81,17 @@ public void setPath(AppInterface options) {
7881
" WHERE " + APP_COLUMN_ID + "=" + options.id);
7982
}
8083

81-
public AppInterface init(AppInterface options) {
84+
public void setWSAddress(AppInterface options) {
85+
Log.d("INFO", "Update WS address " + options.wsAddress + " with id " + options.id);
86+
db.execSQL("UPDATE " + TABLE_NAME +
87+
" SET " + APP_COLUMN_WS_ADDRESS + "='" + options.wsAddress + "'" +
88+
" WHERE " + APP_COLUMN_ID + "=" + options.id);
89+
}
90+
91+
public AppInterface init() {
8292
// String selection = APP_COLUMN_ID + "=?";
8393
// String[] selectionArgs = {"%" + id + "%"};
94+
AppInterface options = new AppInterface();
8495
Cursor cursor = db.query(
8596
TABLE_NAME,
8697
projections,
@@ -98,15 +109,17 @@ public AppInterface init(AppInterface options) {
98109
APP_COLUMN_ID + ", " +
99110
APP_COLUMN_URL + ", " +
100111
APP_COLUMN_URL_DEFAULT + ", " +
101-
APP_COLUMN_PATH + ") " +
112+
APP_COLUMN_PATH + ", " +
113+
APP_COLUMN_WS_ADDRESS + ") " +
102114
"VALUES" +
103115
" (" +
104-
null + ", '" +
116+
options.id + ", '" +
105117
options.url + "', '" +
106118
options.urlDefault + "', '" +
107-
options.path + "')"
119+
options.path + "', '" +
120+
options.wsAddress + "')"
108121
);
109-
return init(options);
122+
return init();
110123
}
111124
if (count != 1) {
112125
Log.w(TAG,"App cursor count is " + count);
@@ -118,6 +131,7 @@ public AppInterface init(AppInterface options) {
118131
schema.url = cursor.getString(getAppColumnIndex(APP_COLUMN_URL));
119132
schema.urlDefault = cursor.getString(getAppColumnIndex(APP_COLUMN_URL_DEFAULT));
120133
schema.path = cursor.getString(getAppColumnIndex(APP_COLUMN_PATH));
134+
schema.wsAddress = cursor.getString(getAppColumnIndex(APP_COLUMN_WS_ADDRESS));
121135
}
122136
return schema;
123137
}
@@ -127,24 +141,25 @@ public AppInterface init(AppInterface options) {
127141

128142

129143
public class DB extends SQLiteOpenHelper {
130-
131144
SQLiteDatabase sqLiteDatabase;
132-
133145
App app;
134-
135-
136-
137-
MainActivity context;
138-
139146
public DB(MainActivity _context) {
140147
super(_context, Config.DATABASE_NAME, null, Config.DATABASE_VERSION);
141-
context = _context;
142148
sqLiteDatabase = getWritableDatabase();
143149
app = new App(sqLiteDatabase);
144150
app.onCreate();
145151
onCreate(sqLiteDatabase);
146152
}
147153

154+
public String getUrl() {
155+
AppInterface schemaApp = app.init();
156+
String url = schemaApp.url;
157+
if (url.equals("null")) {
158+
url = schemaApp.urlDefault;
159+
}
160+
return url;
161+
}
162+
148163
@Override
149164
public void onCreate(SQLiteDatabase _sqLiteDatabase) {
150165
sqLiteDatabase = _sqLiteDatabase;
Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
package com.kolserdav.ana;
2+
3+
import android.app.PendingIntent;
4+
import android.content.Intent;
5+
import android.app.Service;
6+
import android.net.Uri;
7+
import android.os.*;
8+
import android.util.Log;
9+
10+
import androidx.annotation.Nullable;
11+
import androidx.core.app.NotificationCompat;
12+
import androidx.core.app.NotificationManagerCompat;
13+
14+
import org.java_websocket.handshake.ServerHandshake;
15+
import org.json.JSONException;
16+
import org.json.JSONObject;
17+
18+
import java.net.URI;
19+
import java.net.URISyntaxException;
20+
21+
22+
public class DisplayNotification extends Service {
23+
24+
private final String TAG = "DisplayNotification";
25+
26+
public static final String INTENT_EXTRA_NAME_URL = "url";
27+
28+
public static final String INTENT_EXTRA_NAME_WS_ADDRESS = "ws_address";
29+
30+
public static final String INTENT_EXTRA_NAME_NOTIFICATION_UNIT_ID = "notification_unit_id";
31+
32+
private String wsAddress = null;
33+
34+
private String url = null;
35+
36+
private String unitId = null;
37+
38+
public void createNotification(String title, String content, String path) {
39+
Intent intent = new Intent(this, MainActivity.class);
40+
intent.setData(Uri.parse(url + path));
41+
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
42+
int requestID = (int) System.currentTimeMillis();
43+
int flags = PendingIntent.FLAG_UPDATE_CURRENT;
44+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
45+
flags = PendingIntent.FLAG_IMMUTABLE;
46+
}
47+
PendingIntent pendingIntent = PendingIntent.getActivity(this, requestID, intent, flags);
48+
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, Config.CHANNEL_ID)
49+
.setSmallIcon(R.mipmap.ic_launcher)
50+
.setContentTitle(title)
51+
.setContentIntent(pendingIntent)
52+
.setAutoCancel(true)
53+
.setStyle(new NotificationCompat.BigTextStyle()
54+
.bigText(content))
55+
56+
.setPriority(NotificationCompat.PRIORITY_DEFAULT);
57+
NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);
58+
notificationManager.notify(requestID, builder.build());
59+
}
60+
61+
private void listenNotifications() {
62+
URI uri = null;
63+
try {
64+
uri = new URI(wsAddress);
65+
} catch (URISyntaxException e) {
66+
Log.e(TAG, "Error create WebSocket URI: " + e.getMessage());
67+
}
68+
69+
if (uri != null) {
70+
WebSocket ws = new WebSocket(uri) {
71+
@Override
72+
public void onOpen(ServerHandshake handshake) {
73+
super.onOpen(handshake);
74+
JSONObject obj = new JSONObject();
75+
try {
76+
obj.put("message", Config.WS_MESSAGE_NOTIFICATION_USER_ID);
77+
obj.put("data", unitId);
78+
} catch (JSONException e) {
79+
Log.e(TAG, "Failed create JSON object: " + e.getMessage());
80+
}
81+
send(obj.toString());
82+
}
83+
84+
@Override
85+
public void onClose(int code, String reason, boolean remote) {
86+
super.onClose(code, reason, remote);
87+
try {
88+
Thread.sleep(Config.WS_RECONNECT_TIMEOUT);
89+
} catch (InterruptedException e) {
90+
Log.e(TAG, "Failed wait reconnect WS: " + e.getMessage());
91+
}
92+
listenNotifications();
93+
}
94+
95+
@Override
96+
public void onMessage(String message) {
97+
super.onMessage(message);
98+
JSONObject data = null;
99+
try {
100+
data = new JSONObject(message);
101+
} catch (JSONException e) {
102+
Log.e(TAG, "Failed parse WS message: " + e.getMessage());
103+
}
104+
if (data != null) {
105+
try {
106+
String title = data.get("type").toString();
107+
String content = data.get("message").toString();
108+
String path = data.get("data").toString();
109+
createNotification(title, content, path);
110+
} catch (JSONException e) {
111+
Log.e(TAG, "Failed parse WS message: " + e.getMessage());
112+
}
113+
}
114+
}
115+
};
116+
ws.connect();
117+
}
118+
}
119+
120+
@Override
121+
public void onCreate() {
122+
super.onCreate();
123+
Thread thread = new Thread() {
124+
@Override
125+
public void run() {
126+
super.run();
127+
while (url == null) {}
128+
Log.d(TAG, "Notifications service is running: " + wsAddress + ", " + url);
129+
listenNotifications();
130+
}
131+
};
132+
thread.start();
133+
}
134+
135+
@Nullable
136+
@Override
137+
public IBinder onBind(Intent intent) {
138+
return null;
139+
}
140+
141+
@Override
142+
public int onStartCommand(Intent intent, int flags, int startId) {
143+
Bundle extras = intent.getExtras();
144+
if (extras == null) {
145+
Log.w(TAG, "Extras is null");
146+
} else {
147+
wsAddress = extras.get(INTENT_EXTRA_NAME_WS_ADDRESS).toString();
148+
url = extras.get(INTENT_EXTRA_NAME_URL).toString();
149+
unitId = extras.get(INTENT_EXTRA_NAME_NOTIFICATION_UNIT_ID).toString();
150+
}
151+
return super.onStartCommand(intent, flags, startId);
152+
}
153+
154+
@Override
155+
public void onDestroy() {
156+
super.onDestroy();
157+
Log.d(TAG, "Service destroyed");
158+
}
159+
}

0 commit comments

Comments
 (0)