feat: Add an API for creating direct share shortcuts

This commit is contained in:
2023-07-21 13:04:44 +02:00
parent 3bc880079c
commit 052a4e4700
26 changed files with 368 additions and 36 deletions

View File

@@ -25,8 +25,8 @@ android {
compileSdkVersion 31
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
sourceCompatibility JavaVersion.VERSION_14
targetCompatibility JavaVersion.VERSION_14
}
defaultConfig {
@@ -36,4 +36,5 @@ android {
dependencies {
implementation 'androidx.localbroadcastmanager:localbroadcastmanager:1.0.0'
implementation 'androidx.core:core:1.10.1'
}

View File

@@ -1,5 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-7.2-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

View File

@@ -6,17 +6,28 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.Icon;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.core.app.Person;
import androidx.core.content.ContextCompat;
import androidx.core.content.pm.ShortcutInfoCompat;
import androidx.core.content.pm.ShortcutManagerCompat;
import androidx.core.graphics.drawable.IconCompat;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import java.io.FileInputStream;
import java.security.MessageDigest;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import javax.crypto.Cipher;
import javax.crypto.CipherOutputStream;
@@ -191,12 +202,79 @@ public class MoxplatformAndroidPlugin extends BroadcastReceiver implements Flutt
});
hashingThread.start();
break;
case "recordSentMessage":
ArrayList rargs = (ArrayList) call.arguments;
try {
recordSentMessage(
(String) rargs.get(0),
(String) rargs.get(1),
(String) rargs.get(2),
(int) rargs.get(3)
);
} catch (ClassNotFoundException ex) {
Log.e(TAG, "Failed to get classname");
Log.e(TAG, ex.getMessage());
}
result.success(true);
break;
default:
result.notImplemented();
break;
}
}
private void recordSentMessage(String name, String jid, String avatarPath, int fallbackIconType) throws ClassNotFoundException {
// Very much inspired (or copied) from https://github.com/ShoutSocial/share_handler
final String pkgName = context.getPackageName();
final Intent intent = new Intent(context, Class.forName(pkgName + ".MainActivity"));
intent.setAction(Intent.ACTION_SEND);
// Compatibility with share_handler
intent.putExtra("conversationIdentifier", jid);
final String shortcutTarget = pkgName + ".dynamic_share_target";
final ShortcutInfoCompat.Builder builder = new ShortcutInfoCompat.Builder(context, name);
builder
.setShortLabel(name)
.setIsConversation()
.setCategories(Set.of(shortcutTarget))
.setIntent(intent)
.setLongLived(true);
// TODO: This is dumb. Maybe just raise the minimum Android version
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
final Person.Builder personBuilder = new Person.Builder()
.setKey(jid)
.setName(name);
if (avatarPath != null) {
final Bitmap bitmap = BitmapFactory.decodeFile(avatarPath);
final IconCompat icon = IconCompat.createWithAdaptiveBitmap(bitmap);
builder.setIcon(icon);
personBuilder.setIcon(icon);
} else {
if (fallbackIconType == 0 || fallbackIconType == 1) {
final int id = switch (fallbackIconType) {
default:
case 0: yield R.mipmap.person;
case 1: yield R.mipmap.notes;
};
final IconCompat personIcon = IconCompat.createWithResource(
context,
id
);
builder.setIcon(personIcon);
personBuilder.setIcon(personIcon);
}
}
builder.setPerson(personBuilder.build());
}
final ShortcutInfoCompat shortcut = builder.build();
ShortcutManagerCompat.addDynamicShortcuts(context, List.of(shortcut));
}
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction() == null) return;

View File

@@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="120dp"
android:height="120dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group android:scaleX="0.42988887"
android:scaleY="0.42988887"
android:translateX="6.8413334"
android:translateY="6.8413334">
<path
android:pathData="M3,18h12v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h18v-2L3,11v2z"
android:fillColor="#ffffff"/>
</group>
</vector>

View File

@@ -0,0 +1,14 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="120dp"
android:height="120dp"
android:viewportWidth="24"
android:viewportHeight="24">
<group android:scaleX="0.483625"
android:scaleY="0.483625"
android:translateX="6.1965"
android:translateY="6.1965">
<path
android:pathData="m12,12c2.21,0 4,-1.79 4,-4C16,5.79 14.21,4 12,4 9.79,4 8,5.79 8,8c0,2.21 1.79,4 4,4zM12,14c-2.67,0 -8,1.34 -8,4v2h16v-2c0,-2.66 -5.33,-4 -8,-4z"
android:fillColor="#fffff9"/>
</group>
</vector>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/notes_background"/>
<foreground android:drawable="@drawable/notes_foreground"/>
</adaptive-icon>

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@color/person_background"/>
<foreground android:drawable="@drawable/person_foreground"/>
</adaptive-icon>

Binary file not shown.

After

Width:  |  Height:  |  Size: 650 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="notes_background">#CF4AFF</color>
</resources>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="person_background">#CF4AFF</color>
</resources>