Skip to content

Commit b1a4783

Browse files
committed
Merge branch 'feature/group_sharing' into 'master'
Feature: Group Sharing See merge request app-frameworks/esp-rainmaker-android!96
2 parents d5e0b56 + 0038ec7 commit b1a4783

29 files changed

+2777
-140
lines changed

README.md

+18
Original file line numberDiff line numberDiff line change
@@ -119,6 +119,24 @@ Sharing can be enabled/disabled by setting true/false value of `isNodeSharingSup
119119
Sharing feature is optional but enabled by default.
120120
Add `isNodeSharingSupported=false` in `local.properties` file to disable this feature.
121121

122+
### Group Sharing
123+
124+
Group sharing allows a user to share groups with other registered users and allow them to monitor and control nodes of the shared group.
125+
List of operations that are supported in group sharing :
126+
127+
For primary users:
128+
- Register requests to share groups.
129+
- Share a group with full access.
130+
- View pending requests.
131+
- Cancel a pending request, if required.
132+
- Remove group sharing.
133+
134+
For secondary users:
135+
- View pending requests.
136+
- Accept/decline pending requests.
137+
- Control nodes which are in shared group.
138+
- Leave a group.
139+
122140
### Device Automation
123141

124142
Device Automation is a set of actions that will be triggered based on the completion of certain events. For example, the user can set an event as the Temperature sensor equals 35 degrees celsius. Then based on this event user can trigger different actions like Switching on AC or Setting the AC temperature to 20 degrees celsius or a combination of both.

app/build.gradle

+2-2
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ android {
5555
applicationId "com.espressif.rainmaker"
5656
minSdkVersion 27
5757
targetSdkVersion 34
58-
versionCode 126
59-
versionName "3.3.4 - ${getGitHash()}"
58+
versionCode 128
59+
versionName "3.4.0 - ${getGitHash()}"
6060
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
6161

6262
buildConfigField "String", "GitHash", "\"${getGitHash()}\""

app/src/main/AndroidManifest.xml

+13-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="utf-8"?>
22
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3-
xmlns:tools="http://schemas.android.com/tools">>
3+
xmlns:tools="http://schemas.android.com/tools">
44

55
<uses-permission android:name="android.permission.CAMERA" />
66
<uses-permission android:name="android.permission.VIBRATE" />
@@ -253,6 +253,11 @@
253253
android:label="@string/title_activity_about"
254254
android:screenOrientation="portrait"
255255
android:theme="@style/AppTheme.NoActionBar" />
256+
<activity
257+
android:name="com.espressif.ui.activities.GroupShareActivity"
258+
android:label="@string/title_activity_group_sharing_requests"
259+
android:screenOrientation="portrait"
260+
android:theme="@style/AppTheme.NoActionBar" />
256261
<activity
257262
android:name="com.espressif.ui.activities.TimeSeriesActivity"
258263
android:label="@string/title_activity_about"
@@ -298,8 +303,15 @@
298303
android:screenOrientation="portrait"
299304
android:theme="@style/AppTheme.NoActionBar" />
300305

306+
<activity android:name="com.espressif.ui.activities.GroupInfoActivity"
307+
android:label="@string/title_activity_group_detail"
308+
android:screenOrientation="portrait"
309+
android:theme="@style/AppTheme.NoActionBar"/>
310+
301311
<receiver android:name="com.espressif.NodeSharingActionReceiver" />
302312

313+
<receiver android:name="com.espressif.GroupSharingActionReceiver" />
314+
303315
<service
304316
android:name="com.espressif.matter.AppCommissioningService"
305317
android:exported="true" />

app/src/main/java/com/espressif/AppConstants.kt

+16
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ class AppConstants {
142142
const val CHANNEL_ALERT = "notify_alert_id"
143143
const val CHANNEL_NODE_SHARING = "notify_node_sharing_id"
144144
const val CHANNEL_NODE_AUTOMATION_TRIGGER = "notify_node_automation_trigger"
145+
const val CHANNEL_GROUP_SHARING = "notify_group_sharing_id"
145146

146147
// Notification button actions
147148
const val ACTION_ACCEPT = "com.espressif.rainmaker.ACTION_ACCEPT"
@@ -156,6 +157,9 @@ class AppConstants {
156157
const val EVENT_NODE_PARAM_MODIFIED = "rmaker.event.node_params_changed"
157158
const val EVENT_ALERT = "rmaker.event.alert"
158159
const val EVENT_NODE_AUTOMATION_TRIGGER = "rmaker.event.node_automation_trigger"
160+
const val EVENT_GROUP_SHARING_ADD = "rmaker.event.user_node_group_sharing_add"
161+
const val EVENT_GROUP_SHARE_ADDED = "rmaker.event.user_node_group_added"
162+
const val EVENT_GROUP_SHARE_REMOVED = "rmaker.event.user_node_group_removed"
159163

160164
/* App related constants */
161165

@@ -218,6 +222,9 @@ class AppConstants {
218222
const val URL_NODE_OTA_UPDATE = "/user/nodes/ota_update"
219223
const val URL_NODE_OTA_STATUS = "/user/nodes/ota_status"
220224

225+
const val URL_USER_NODE_GROUP_SHARING = "/user/node_group/sharing"
226+
const val URL_USER_NODE_GROUP_SHARING_REQUESTS = "/user/node_group/sharing/requests"
227+
221228
// Alexa account linking constants
222229
const val ALEXA_API_ENDPOINTS_URL = "https://api.amazonalexa.com/v1/alexaApiEndpoint"
223230
const val ALEXA_REFRESH_TOKEN_URL = "https://api.amazon.com/auth/o2/token"
@@ -305,6 +312,8 @@ class AppConstants {
305312
const val KEY_GROUP = "group"
306313
const val KEY_NODE_IDS = "node_ids"
307314
const val KEY_NODE_SHARING = "node_sharing"
315+
const val KEY_GROUP_SHARING = "group_sharing"
316+
const val KEY_SOURCES = "sources"
308317
const val KEY_USERS = "users"
309318
const val KEY_PRIMARY_USER = "primary_user"
310319
const val KEY_START_REQ_ID = "start_request_id"
@@ -351,6 +360,10 @@ class AppConstants {
351360
const val KEY_SYSTEM = "System"
352361
const val KEY_MATTER_CONTROLLER = "Matter-Controller"
353362
const val KEY_REACHABLE = "reachable"
363+
const val KEY_SHARED_FROM = "shared_from"
364+
const val KEY_SHARED_TO = "shared_to"
365+
const val KEY_SELF_REMOVAL = "self_removal"
366+
const val KEY_NODE = "NODE"
354367

355368
const val KEY_OPERATION = "operation"
356369
const val KEY_OPERATION_ADD = "add"
@@ -407,6 +420,9 @@ class AppConstants {
407420
const val KEY_OTA_DETAILS = "ota_details"
408421
const val KEY_OTA_AVAILABLE = "ota_available"
409422

423+
const val KEY_GROUP_NAMES = "group_names"
424+
const val KEY_GROUP_IDS = "group_ids"
425+
410426
const val KEY_MUTUALLY_EXCLUSIVE = "mutually_exclusive"
411427
const val KEY_IS_MATTER = "is_matter"
412428
const val KEY_ROOT_CA = "root_ca"

app/src/main/java/com/espressif/EspApplication.java

+4
Original file line numberDiff line numberDiff line change
@@ -1213,6 +1213,9 @@ private void setupNotificationChannels() {
12131213
NotificationChannel automationChannel = new NotificationChannel(AppConstants.CHANNEL_NODE_AUTOMATION_TRIGGER,
12141214
getString(R.string.channel_node_automation_trigger), NotificationManager.IMPORTANCE_HIGH);
12151215

1216+
NotificationChannel groupSharingChannel = new NotificationChannel(AppConstants.CHANNEL_GROUP_SHARING,
1217+
getString(R.string.channel_node_group_sharing), NotificationManager.IMPORTANCE_HIGH);
1218+
12161219
NotificationManager notificationManager = getSystemService(NotificationManager.class);
12171220
notificationManager.createNotificationChannel(nodeConnectedChannel);
12181221
notificationManager.createNotificationChannel(nodeDisconnectedChannel);
@@ -1221,6 +1224,7 @@ private void setupNotificationChannels() {
12211224
notificationManager.createNotificationChannel(nodeSharingChannel);
12221225
notificationManager.createNotificationChannel(alertChannel);
12231226
notificationManager.createNotificationChannel(automationChannel);
1227+
notificationManager.createNotificationChannel(groupSharingChannel);
12241228
}
12251229
}
12261230

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package com.espressif;
16+
17+
import android.content.BroadcastReceiver;
18+
import android.content.Context;
19+
import android.content.Intent;
20+
import android.os.Bundle;
21+
import android.text.TextUtils;
22+
import android.util.Log;
23+
import android.widget.Toast;
24+
25+
import androidx.annotation.NonNull;
26+
import androidx.annotation.Nullable;
27+
import androidx.core.app.NotificationManagerCompat;
28+
29+
import com.espressif.cloudapi.ApiManager;
30+
import com.espressif.cloudapi.ApiResponseListener;
31+
import com.espressif.cloudapi.CloudException;
32+
import com.espressif.rainmaker.R;
33+
import com.espressif.ui.activities.GroupDetailActivity;
34+
import com.espressif.ui.activities.SplashActivity;
35+
36+
public class GroupSharingActionReceiver extends BroadcastReceiver {
37+
38+
private static final String TAG = "GroupSharingReceiver";
39+
40+
@Override
41+
public void onReceive(Context context, Intent intent) {
42+
43+
String action = intent.getAction();
44+
String requestId = intent.getStringExtra(AppConstants.KEY_REQ_ID);
45+
int notificationId = intent.getIntExtra(AppConstants.KEY_ID, 0);
46+
47+
if (!TextUtils.isEmpty(requestId)) {
48+
49+
if (AppConstants.ACTION_ACCEPT.equals(action)) {
50+
51+
ApiManager.getInstance(context).updateGroupSharingRequest(requestId, true, new ApiResponseListener() {
52+
53+
@Override
54+
public void onSuccess(@Nullable Bundle data) {
55+
56+
Log.d(TAG, "Group sharing accepted.");
57+
NotificationManagerCompat.from(context).cancel(notificationId);
58+
Intent splashIntent = new Intent(context, SplashActivity.class);
59+
splashIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
60+
context.startActivity(splashIntent);
61+
}
62+
63+
@Override
64+
public void onResponseFailure(@NonNull Exception exception) {
65+
66+
if (exception instanceof CloudException) {
67+
Toast.makeText(context, exception.getMessage(), Toast.LENGTH_SHORT).show();
68+
} else {
69+
Toast.makeText(context, "Failed to accept group sharing due to response failure", Toast.LENGTH_SHORT).show();
70+
}
71+
}
72+
73+
@Override
74+
public void onNetworkFailure(@NonNull Exception exception) {
75+
76+
if (exception instanceof CloudException) {
77+
Toast.makeText(context, exception.getMessage(), Toast.LENGTH_SHORT).show();
78+
} else {
79+
Toast.makeText(context, "Failed to accept group sharing due to network failure", Toast.LENGTH_SHORT).show();
80+
}
81+
}
82+
});
83+
} else if (AppConstants.ACTION_DECLINE.equals(action)) {
84+
85+
ApiManager.getInstance(context).updateGroupSharingRequest(requestId, false, new ApiResponseListener() {
86+
@Override
87+
public void onSuccess(@Nullable Bundle data) {
88+
89+
Log.d(TAG, "Group sharing declined.");
90+
NotificationManagerCompat.from(context).cancel(notificationId);
91+
}
92+
93+
@Override
94+
public void onResponseFailure(@NonNull Exception exception) {
95+
96+
if (exception instanceof CloudException) {
97+
Toast.makeText(context, exception.getMessage(), Toast.LENGTH_SHORT).show();
98+
} else {
99+
Toast.makeText(context, "Failed to decline group sharing due to response failure", Toast.LENGTH_SHORT).show();
100+
}
101+
}
102+
103+
@Override
104+
public void onNetworkFailure(@NonNull Exception exception) {
105+
106+
if (exception instanceof CloudException) {
107+
Toast.makeText(context, exception.getMessage(), Toast.LENGTH_SHORT).show();
108+
} else {
109+
Toast.makeText(context, "Failed to decline group sharing due to network failure", Toast.LENGTH_SHORT).show();
110+
}
111+
}
112+
});
113+
}
114+
}
115+
}
116+
}

0 commit comments

Comments
 (0)