Browse Source

Merge pull request 'Android Notification - First Cut' (#391) from android_tests into master

Reviewed-on: https://git.openprivacy.ca/cwtch.im/ui/pulls/391
pull/393/head
Dan Ballard 3 months ago
parent
commit
3d509c6810
8 changed files with 66 additions and 80 deletions
  1. +8
    -1
      ANDROID_DEBUGGING.md
  2. +28
    -54
      android/src/ca/openprivacy/cwtch/ui/CwtchActivity.java
  3. +0
    -1
      go/handlers/peerHandler.go
  4. +3
    -17
      go/ui/android/CwtchActivity.go
  5. +4
    -0
      go/ui/gcd.go
  6. +9
    -0
      go/ui/manager.go
  7. +4
    -7
      main.go
  8. +10
    -0
      qml/main.qml

+ 8
- 1
ANDROID_DEBUGGING.md View File

@@ -79,4 +79,11 @@ Theoretically speaking it should be possible to use `ANDROID_EXTRA_PLUGINS` to i
SVG images on Android. However, we have been unable to make it work. If you would like to try, the following
issues might be helpful:

* https://bugreports.qt.io/browse/QTBUG-60022
* https://bugreports.qt.io/browse/QTBUG-60022

## Notifications

- Android 8 (API Level 26) forces you to call setChannelId()
- Android 9 "Do Not Disturb" mode also hides all notifications
- Setting up notification channels only seems possible *once* per install. any changes you need to make
require that the app is reinstalled, or the actual channel deleted and changed.

+ 28
- 54
android/src/ca/openprivacy/cwtch/ui/CwtchActivity.java View File

@@ -23,20 +23,13 @@ import static android.app.Notification.CATEGORY_SERVICE;
public class CwtchActivity extends org.qtproject.qt5.android.bindings.QtActivity
{
private static NotificationManager m_notificationManager;
private static Notification.Builder m_builder;
private static Notification.Builder m_builderOngoing;
private static CwtchActivity m_instance;

private static int PRIORITY_MIN = -2; // From NotificationCompat
private static int PRIORITY_DEFAULT = 0; // From NotificationCompat

private static String NOTIFICATION_CHANNEL_ID = "cwtch_notification_channel";
private static int CONTENT_NOTIFICATION_ID = 2;
private static String CONTENT_NOTIFICATION_ID_NAME = "Notifications from Peers";

private static int ONGOING_NOTIFICATION_ID = 0;
private static String ONGOING_NOTIFICATION_ID_NAME = "ongoing";

private static int CONTENT_NOTIFICATION_ID = 1;
private static String CONTENT_NOTIFICATION_ID_NAME = "content";


public CwtchActivity() {
@@ -57,66 +50,47 @@ public class CwtchActivity extends org.qtproject.qt5.android.bindings.QtActivity
}
}

public static void notify(String s)
public static void notify(String s, String o)
{
if (m_notificationManager == null) {
m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE);
createNotificationChannel();
}

if (m_builder == null) {
m_builder = new Notification.Builder(m_instance);
m_builder.setSmallIcon(R.drawable.ic_launcher);
m_builder.setContentTitle("Cwtch");
m_builder.setPriority(PRIORITY_DEFAULT);
// Apparently thr android documentation is just wrong and we need to provide a setGroupSummary
// notification regardless of targetted support version...
Notification groupSummary =
new Notification.Builder(m_instance)
.setContentTitle("Cwtch")
.setContentText("New Message from Peer: " + o)
.setGroupSummary(true)
.setWhen(System.currentTimeMillis())
.setSmallIcon(R.drawable.ic_launcher)
.setGroup(NOTIFICATION_CHANNEL_ID)
.setChannelId(NOTIFICATION_CHANNEL_ID)
.build();
m_notificationManager.notify(1, groupSummary);

Notification.Builder m_builder = new Notification.Builder(m_instance)
.setSmallIcon(R.drawable.ic_launcher)
.setChannelId(NOTIFICATION_CHANNEL_ID)
.setGroup(NOTIFICATION_CHANNEL_ID)
.setWhen(System.currentTimeMillis())
.setAutoCancel(true)
.setContentTitle("New Message from Peer: " + o)
.setContentText("[redacted: Open Cwtch App to see the Message]");
m_notificationManager.notify(CONTENT_NOTIFICATION_ID++, m_builder.build());

}

m_builder.setContentText(s);
m_notificationManager.notify(CONTENT_NOTIFICATION_ID, m_builder.build());
}

public static void ongoingNotify(String s)
{
if (m_notificationManager == null) {
m_notificationManager = (NotificationManager)m_instance.getSystemService(Context.NOTIFICATION_SERVICE);
createNotificationChannel();
}

if (m_builderOngoing == null) {
m_builderOngoing = new Notification.Builder(m_instance);
m_builderOngoing.setSmallIcon(R.drawable.ic_launcher);
m_builderOngoing.setContentTitle("Cwtch");
m_builderOngoing.setPriority(PRIORITY_MIN);

m_builderOngoing.setWhen(0); // Don't show the time
m_builderOngoing.setOngoing(true);
if (SDK_INT >= 21) {
m_builderOngoing.setCategory(CATEGORY_SERVICE);
//m_builder.setVisibility(VISIBILITY_SECRET);
}

}

m_builderOngoing.setContentText(s);
m_notificationManager.notify(ONGOING_NOTIFICATION_ID, m_builderOngoing.build());
}

private static void createNotificationChannel() {
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
if (SDK_INT >= 26) {
String description = "Cwtch Ongoing Notification Channel";
int importance = NotificationManager.IMPORTANCE_LOW;
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, ONGOING_NOTIFICATION_ID_NAME, importance);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this
m_notificationManager.createNotificationChannel(channel);

description = "Cwtch Content Notification Channel";
importance = NotificationManager.IMPORTANCE_DEFAULT;
channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, CONTENT_NOTIFICATION_ID_NAME, importance);
String description = "Cwtch Notification Channel";
NotificationChannel channel = new NotificationChannel(NOTIFICATION_CHANNEL_ID, CONTENT_NOTIFICATION_ID_NAME, NotificationManager.IMPORTANCE_HIGH);
channel.setDescription(description);
// Register the channel with the system; you can't change the importance
// or other notification behaviors after this


+ 0
- 1
go/handlers/peerHandler.go View File

@@ -58,7 +58,6 @@ func PeerHandler(onion string, uiManager ui.Manager, subscribed chan bool) {
case event.NewMessageFromPeer: //event.TimestampReceived, event.RemotePeer, event.Data
ts, _ := time.Parse(time.RFC3339Nano, e.Data[event.TimestampReceived])
uiManager.StoreAndNotify(peer, e.Data[event.RemotePeer], e.Data[event.Data], ts, onion)

case event.PeerAcknowledgement:
uiManager.Acknowledge(e.Data[event.RemotePeer], e.Data[event.EventID])



+ 3
- 17
go/ui/android/CwtchActivity.go View File

@@ -11,6 +11,7 @@ type CwtchActivity struct {

_ func() `constructor:"init"`

_ string `property:"channel"`
_ string `property:"notification"`

_ func(string) `slot:"updateAndroidNotification"`
@@ -20,7 +21,6 @@ type CwtchActivity struct {

func (c *CwtchActivity) init() {
log.Debugln("CwtchActivity.init()")
c.createOngoingNotification()
c.ConnectNotificationChanged(c.updateAndroidNotification)
}

@@ -29,8 +29,8 @@ func (c *CwtchActivity) updateAndroidNotification(n string) {
var err = androidextras.QAndroidJniObject_CallStaticMethodVoid2Caught(
"ca/openprivacy/cwtch/ui/CwtchActivity",
"notify",
"(Ljava/lang/String;)V",
n,
"(Ljava/lang/String;Ljava/lang/String;)V",
n, c.Channel(),
)

if err != nil {
@@ -38,20 +38,6 @@ func (c *CwtchActivity) updateAndroidNotification(n string) {
}
}

func (c *CwtchActivity) createOngoingNotification() {

var err = androidextras.QAndroidJniObject_CallStaticMethodVoid2Caught(
"ca/openprivacy/cwtch/ui/CwtchActivity",
"ongoingNotify",
"(Ljava/lang/String;)V",
"Cwtch is running",
)

if err != nil {
log.Errorf("Error calling Java CwtchActivity.ongoingNotify(): %v\n", err.Error())
}
}

func (c *CwtchActivity) rootHomeButtonHandle() {
log.Infoln("CwtchActivity.rootHomeButtonHandle()!")
var err = androidextras.QAndroidJniObject_CallStaticMethodVoid2Caught(


+ 4
- 0
go/ui/gcd.go View File

@@ -8,6 +8,7 @@ import (
"cwtch.im/cwtch/protocol/connections"
"cwtch.im/ui/go/constants"
"cwtch.im/ui/go/features/groups"
"cwtch.im/ui/go/ui/android"
"github.com/therecipe/qt/qml"
"strconv"
"sync"
@@ -22,6 +23,7 @@ import (
type GrandCentralDispatcher struct {
core.QObject

AndroidCwtchActivity *android.CwtchActivity
QMLEngine *qml.QQmlApplicationEngine
Translator, OpaqueTranslator *core.QTranslator

@@ -58,6 +60,7 @@ type GrandCentralDispatcher struct {
_ func() `signal:"ResetProfileList"`
_ func(failed bool) `signal:"ChangePasswordResponse"`
_ func(onion string, online bool) `signal:"UpdateProfileNetworkStatus"`
_ func(onion string) `signal:"Notify"`

// server management
_ func(handle, displayname, image string, status int, autostart bool, bundle string, messages int, key_types []string, keys []string) `signal:"AddServer"`
@@ -147,6 +150,7 @@ func (this *GrandCentralDispatcher) init() {
this.SetTheme(this.GlobalSettings.Theme)
this.SetExperimentsEnabled(this.GlobalSettings.ExperimentsEnabled)
this.SetExperiments(this.GlobalSettings.Experiments)
this.AndroidCwtchActivity = android.NewCwtchActivity(nil)
}

// GetUiManager gets (and creates if required) a ui Manager for the supplied profile id


+ 9
- 0
go/ui/manager.go View File

@@ -301,6 +301,11 @@ func (this *manager) MessageJustAdded() {
}

func (this *manager) StoreAndNotify(pere peer.CwtchPeer, onion string, messageTxt string, sent time.Time, profileOnion string) {

// Send a New Message from Peer Notification
this.gcd.AndroidCwtchActivity.SetChannel(onion)
this.gcd.AndroidCwtchActivity.NotificationChanged("New Message from Peer")

this.gcd.DoIfProfileElse(this.profile, func() {
this.gcd.DoIfConversationElse(onion, func() {
this.gcd.TimelineInterface.AddMessage(this.gcd.TimelineInterface.num())
@@ -314,6 +319,7 @@ func (this *manager) StoreAndNotify(pere peer.CwtchPeer, onion string, messageTx
}, func() {
the.CwtchApp.GetPeer(profileOnion).StoreMessage(onion, messageTxt, sent)
})
this.gcd.Notify(onion)
}

// AddMessage adds a message to the message pane for the supplied conversation if it is active
@@ -331,6 +337,9 @@ func (this *manager) AddMessage(handle string, from string, message string, from
})
this.gcd.IncContactUnreadCount(handle)
})
if !fromMe {
this.gcd.Notify(handle)
}
}

func (this *manager) ReloadProfiles() {


+ 4
- 7
main.go View File

@@ -11,7 +11,6 @@ import (
os2 "cwtch.im/ui/go/os"
"cwtch.im/ui/go/the"
"cwtch.im/ui/go/ui"
"cwtch.im/ui/go/ui/android"
"encoding/base64"
"flag"
"git.openprivacy.ca/openprivacy/connectivity/tor"
@@ -161,6 +160,7 @@ func mainUi(flagLocal bool, flagClientUI bool) {
log.Errorf("Could not access global ui config: %v\n", err)
os.Exit(-1)
}

gcd := ui.NewGrandCentralDispatcher(nil)
gcd.SetOs(runtime.GOOS)
dir := core.QCoreApplication_ApplicationDirPath()
@@ -186,8 +186,6 @@ func mainUi(flagLocal bool, flagClientUI bool) {
gcd.SetBuildDate("now")
}



// this is to load local qml files quickly when developing
var qmlSource *core.QUrl
if flagLocal {
@@ -223,13 +221,13 @@ func mainUi(flagLocal bool, flagClientUI bool) {
return nam
})
engine.SetNetworkAccessManagerFactory(factory)

engine.RootContext().SetContextProperty("gcd", gcd)
gcd.TimelineInterface = ui.NewMessageModel(nil)
engine.RootContext().SetContextProperty("mm", gcd.TimelineInterface)

var androidCwtchActivity = android.NewCwtchActivity(nil)
engine.RootContext().SetContextProperty("androidCwtchActivity", androidCwtchActivity)

engine.RootContext().SetContextProperty("androidCwtchActivity", gcd.AndroidCwtchActivity)


engine.Load(qmlSource)

@@ -263,7 +261,6 @@ func loadACN() {
}
}


// generate a random socks and control port (not real random...these are port numbers...)
mrand.Seed(int64(time.Now().Nanosecond()))
port := mrand.Intn(1000) + 9600


+ 10
- 0
qml/main.qml View File

@@ -419,6 +419,14 @@ ApplicationWindow {
parentStack.updateToolbar()
statusbar.resetHeight()
}

onNotify: function(onion) {
// If we are processing QML it means the app is open, and as such we don't want to
// Send a notification - in the future we should probably use an API like this to Cancel notifications
// Until then I am leaving this here for documentation.
// androidCwtchActivity.channel = onion
// androidCwtchActivity.notification = "Message from " + onion;
}
}

Component.onCompleted: Mutant.standard.imagePath = gcd.assetPath;
@@ -433,4 +441,6 @@ ApplicationWindow {
}
}
}


}

Loading…
Cancel
Save