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

Reviewed-on: #391
This commit is contained in:
Dan Ballard 2020-11-24 17:31:00 -08:00
커밋 3d509c6810
8개의 변경된 파일65개의 추가작업 그리고 79개의 파일을 삭제

파일 보기

@ -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.

파일 보기

@ -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

파일 보기

@ -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])

파일 보기

@ -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(

파일 보기

@ -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

파일 보기

@ -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() {

11
main.go
파일 보기

@ -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

파일 보기

@ -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 {
}
}
}
}