diff --git a/WXGFDecoder/.gitignore b/WXGFDecoder/.gitignore new file mode 100644 index 0000000..1d7e97f --- /dev/null +++ b/WXGFDecoder/.gitignore @@ -0,0 +1,15 @@ +*.iml +.gradle +local.properties +.idea/caches +.idea/libraries +.idea/modules.xml +.idea/workspace.xml +.idea/navEditor.xml +.idea/assetWizardSettings.xml +.DS_Store +build +captures +.externalNativeBuild +.cxx +local.properties diff --git a/WXGFDecoder/app/.gitignore b/WXGFDecoder/app/.gitignore new file mode 100644 index 0000000..378eac2 --- /dev/null +++ b/WXGFDecoder/app/.gitignore @@ -0,0 +1 @@ +build diff --git a/WXGFDecoder/app/build.gradle.kts b/WXGFDecoder/app/build.gradle.kts new file mode 100644 index 0000000..bdf1bf8 --- /dev/null +++ b/WXGFDecoder/app/build.gradle.kts @@ -0,0 +1,55 @@ +import com.android.build.api.dsl.Packaging + +plugins { + alias(libs.plugins.android.application) +} + +android { + namespace = "com.ppwwyyxx.wxgfdecoder" + compileSdk = 35 + + defaultConfig { + applicationId = "com.ppwwyyxx.wxgfdecoder" + minSdk = 24 + targetSdk = 35 + versionCode = 1 + versionName = "1.0" + + testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + signingConfig = signingConfigs.getByName("debug") + } + } + compileOptions { + sourceCompatibility = JavaVersion.VERSION_11 + targetCompatibility = JavaVersion.VERSION_11 + } + buildFeatures { + viewBinding = true + } + packagingOptions { + pickFirst( "jniLibs/arm64-v8a/libvoipCodec.so") + } +} + +dependencies { + implementation("org.java-websocket:Java-WebSocket:1.5.4") + implementation(libs.appcompat) + implementation(libs.material) + implementation(libs.constraintlayout) + implementation(libs.lifecycle.livedata.ktx) + implementation(libs.lifecycle.viewmodel.ktx) + implementation(libs.navigation.fragment) + implementation(libs.navigation.ui) + testImplementation(libs.junit) + androidTestImplementation(libs.ext.junit) + androidTestImplementation(libs.espresso.core) +} diff --git a/WXGFDecoder/app/proguard-rules.pro b/WXGFDecoder/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/WXGFDecoder/app/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/AndroidManifest.xml b/WXGFDecoder/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4e54afd --- /dev/null +++ b/WXGFDecoder/app/src/main/AndroidManifest.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/MainActivity.java b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/MainActivity.java new file mode 100644 index 0000000..093141b --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/MainActivity.java @@ -0,0 +1,227 @@ +package com.ppwwyyxx.wxgfdecoder; + +import android.content.Context; +import android.os.Build; +import android.os.PowerManager; +import android.os.Bundle; +import android.widget.Button; +import android.widget.TextView; +import android.widget.EditText; + +import com.tencent.mm.plugin.gif.MMWXGFJNI; + +import androidx.appcompat.app.AppCompatActivity; + +import com.ppwwyyxx.wxgfdecoder.databinding.ActivityMainBinding; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.net.InetAddress; +import java.net.InetSocketAddress; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.util.Arrays; +import java.net.NetworkInterface; +import java.net.SocketException; +import java.util.Collections; +import java.util.List; + + +import org.java_websocket.WebSocket; +import org.java_websocket.handshake.ClientHandshake; +import org.java_websocket.server.WebSocketServer; + +public class MainActivity extends AppCompatActivity { + + private ActivityMainBinding binding; + private Button startButton; + private TextView hostnameTextView, portTextView, logTextView; + private EditText portEditText; + private WebSocketServer server; + + static { + System.loadLibrary("wechatcommon"); + } + + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + binding = ActivityMainBinding.inflate(getLayoutInflater()); + setContentView(binding.getRoot()); + + // Keep screen on + getWindow().addFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); + // If the app is running on Android 8.0 or higher, request for ignoring battery optimizations + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { + PowerManager powerManager = (PowerManager) getSystemService(Context.POWER_SERVICE); + if (!powerManager.isIgnoringBatteryOptimizations(getPackageName())) { + // TODO: request for ignoring battery optimizations + } + } + + MMWXGFJNI.initialize(getApplicationInfo().nativeLibraryDir); + + // Set up UI + startButton = findViewById(R.id.start_server_button); + hostnameTextView = findViewById(R.id.text_view_hostname); + portTextView = findViewById(R.id.text_view_port); + portEditText = findViewById(R.id.edit_text_port); + logTextView = findViewById(R.id.log_text_area); + logTextView.setText(""); + startButton.setOnClickListener(v -> { + try { + startWebSocketServer(); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + }); + + // Run a unit test: + testWxgfDecoder(); + } + + private void startWebSocketServer() throws InterruptedException { + if (server != null) { + server.stop(); + server = null; + } + + int port; + try { + port = Integer.parseInt(portEditText.getText().toString()); + } catch (NumberFormatException e) { + port = 8080; + } + try { + server = new WebSocketServer(new InetSocketAddress(port)) { + @Override + public void onOpen(WebSocket conn, ClientHandshake handshake) { + printLog("new connection from " + conn.getRemoteSocketAddress().getAddress().getHostAddress()); + } + + @Override + public void onClose(WebSocket conn, int code, String reason, boolean remote) { + printLog("closed " + conn.getRemoteSocketAddress() + " with exit code " + code + " additional info: " + reason); + } + @Override + public void onMessage( WebSocket conn, ByteBuffer message ) { + byte[] msg = message.array(); + + printLog("received binary message from " + conn.getRemoteSocketAddress() + ": size=" + msg.length + + " -- " + Arrays.toString(Arrays.copyOfRange(msg, 0, 10))); + + byte[] res = com.tencent.mm.plugin.gif.MMWXGFJNI.nativeWxam2PicBuf(msg); + if (res != null) { + printLog("After decoding: size=" + res.length + " -- " + + Arrays.toString(Arrays.copyOfRange(res, 0, 10))); + ByteBuffer response = ByteBuffer.wrap(res); + conn.send(response); // the response gif + } else { + printLog("Failed to decode."); + conn.send("FAILED".getBytes()); + } + } + + @Override + public void onMessage( WebSocket conn, String message) { + printLog("Unexpected! received text message from " + conn.getRemoteSocketAddress() + ": " + message); + } + + @Override + public void onError(WebSocket conn, Exception ex) { + printLog("an error occurred on connection " + conn + ":" + ex); + } + + @Override + public void onStart() { + try { + String hostName = getLocalIpAddress(true); + int port = server.getPort(); + printLog("server started successfully at ws://" + hostName + ":" + port); + + runOnUiThread(() -> { // update UI in UI thread + hostnameTextView.setText("Hostname: " + hostName); + portTextView.setText("Port: " + String.valueOf(port)); + }); + } catch (Exception e) { + e.printStackTrace(); + } + } + }; + server.start(); + } catch (Exception e) { + e.printStackTrace(); + } + } + + private void printLog(String log) { + System.out.println(log); + runOnUiThread(() -> { + String currentLog = logTextView.getText().toString(); + logTextView.setText(currentLog + "\n" + log); + }); + } + + public String getLocalIpAddress(boolean useIPv4) throws SocketException { + List interfaces = Collections.list(NetworkInterface.getNetworkInterfaces()); + for (NetworkInterface intf : interfaces) { + List addrs = Collections.list(intf.getInetAddresses()); + for (InetAddress addr : addrs) { + if (!addr.isLoopbackAddress()) { + String sAddr = addr.getHostAddress(); + boolean isIPv4 = sAddr.indexOf(':')<0; + if (useIPv4) { + if (isIPv4) + return sAddr; + } else { + return sAddr; + } + } + } } + return "localhost"; + } + + // Methods below are for debugging the decoder: + private void testWxgfDecoder() { + byte[] wxgf = null; + try { + wxgf = readBinary(this); + } catch (IOException e) { + throw new RuntimeException(e); + } + System.out.println("Unit test: wxgf size=" + wxgf.length); + byte[] res = com.tencent.mm.plugin.gif.MMWXGFJNI.nativeWxam2PicBuf(wxgf); + System.out.println("Unit test: res size=" + res.length + " -- " + Arrays.toString(Arrays.copyOfRange(res, 0, 10))); + + try { + writeFile(this, "test.jpg", res); + } catch (IOException e) { + throw new RuntimeException(e); + } + if (wxgf.length != 64367 || res.length != 705188) { + throw new RuntimeException("test failed"); + } + } + public static byte[] readBinary(Context context) throws IOException { + InputStream inputStream = context.getResources().openRawResource(R.raw.test_wxgf); // R.raw.image refers to your image.jpg file + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + byte[] buffer = new byte[1024]; + int len; + while ((len = inputStream.read(buffer)) != -1) { + byteArrayOutputStream.write(buffer, 0, len); + } + inputStream.close(); // Close the input stream + return byteArrayOutputStream.toByteArray(); + } + + public static void writeFile(Context context, String filename, byte[] data) throws IOException { + File file = new File(context.getExternalFilesDir(null), filename); // Use null for the type argument to get the root external files directory + System.out.println("Writing file to: " + file.getAbsolutePath()); + FileOutputStream outputStream = new FileOutputStream(file); + outputStream.write(data); + outputStream.close(); + } +} diff --git a/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/dashboard/DashboardFragment.java b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/dashboard/DashboardFragment.java new file mode 100644 index 0000000..5d63d38 --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/dashboard/DashboardFragment.java @@ -0,0 +1,37 @@ +package com.ppwwyyxx.wxgfdecoder.ui.dashboard; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; + +import com.ppwwyyxx.wxgfdecoder.databinding.FragmentDashboardBinding; + +public class DashboardFragment extends Fragment { + + private FragmentDashboardBinding binding; + + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + DashboardViewModel dashboardViewModel = + new ViewModelProvider(this).get(DashboardViewModel.class); + + binding = FragmentDashboardBinding.inflate(inflater, container, false); + View root = binding.getRoot(); + + final TextView textView = binding.textDashboard; + dashboardViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); + return root; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } +} \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/dashboard/DashboardViewModel.java b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/dashboard/DashboardViewModel.java new file mode 100644 index 0000000..1b48ad8 --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/dashboard/DashboardViewModel.java @@ -0,0 +1,19 @@ +package com.ppwwyyxx.wxgfdecoder.ui.dashboard; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class DashboardViewModel extends ViewModel { + + private final MutableLiveData mText; + + public DashboardViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is dashboard fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/home/HomeFragment.java b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/home/HomeFragment.java new file mode 100644 index 0000000..c6d4549 --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/home/HomeFragment.java @@ -0,0 +1,34 @@ +package com.ppwwyyxx.wxgfdecoder.ui.home; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; + +import com.ppwwyyxx.wxgfdecoder.databinding.FragmentHomeBinding; + +public class HomeFragment extends Fragment { + + private FragmentHomeBinding binding; + + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + HomeViewModel homeViewModel = + new ViewModelProvider(this).get(HomeViewModel.class); + + binding = FragmentHomeBinding.inflate(inflater, container, false); + View root = binding.getRoot(); + + return root; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } +} \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/home/HomeViewModel.java b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/home/HomeViewModel.java new file mode 100644 index 0000000..7fb867e --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/home/HomeViewModel.java @@ -0,0 +1,19 @@ +package com.ppwwyyxx.wxgfdecoder.ui.home; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class HomeViewModel extends ViewModel { + + private final MutableLiveData mText; + + public HomeViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is home fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/notifications/NotificationsFragment.java b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/notifications/NotificationsFragment.java new file mode 100644 index 0000000..aba83ef --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/notifications/NotificationsFragment.java @@ -0,0 +1,37 @@ +package com.ppwwyyxx.wxgfdecoder.ui.notifications; + +import android.os.Bundle; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +import android.widget.TextView; + +import androidx.annotation.NonNull; +import androidx.fragment.app.Fragment; +import androidx.lifecycle.ViewModelProvider; + +import com.ppwwyyxx.wxgfdecoder.databinding.FragmentNotificationsBinding; + +public class NotificationsFragment extends Fragment { + + private FragmentNotificationsBinding binding; + + public View onCreateView(@NonNull LayoutInflater inflater, + ViewGroup container, Bundle savedInstanceState) { + NotificationsViewModel notificationsViewModel = + new ViewModelProvider(this).get(NotificationsViewModel.class); + + binding = FragmentNotificationsBinding.inflate(inflater, container, false); + View root = binding.getRoot(); + + final TextView textView = binding.textNotifications; + notificationsViewModel.getText().observe(getViewLifecycleOwner(), textView::setText); + return root; + } + + @Override + public void onDestroyView() { + super.onDestroyView(); + binding = null; + } +} \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/notifications/NotificationsViewModel.java b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/notifications/NotificationsViewModel.java new file mode 100644 index 0000000..6f79d11 --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/ppwwyyxx/wxgfdecoder/ui/notifications/NotificationsViewModel.java @@ -0,0 +1,19 @@ +package com.ppwwyyxx.wxgfdecoder.ui.notifications; + +import androidx.lifecycle.LiveData; +import androidx.lifecycle.MutableLiveData; +import androidx.lifecycle.ViewModel; + +public class NotificationsViewModel extends ViewModel { + + private final MutableLiveData mText; + + public NotificationsViewModel() { + mText = new MutableLiveData<>(); + mText.setValue("This is notifications fragment"); + } + + public LiveData getText() { + return mText; + } +} \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/java/com/tencent/mm/plugin/fts/jni/FTSJNIUtils.java b/WXGFDecoder/app/src/main/java/com/tencent/mm/plugin/fts/jni/FTSJNIUtils.java new file mode 100644 index 0000000..a3aee9d --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/tencent/mm/plugin/fts/jni/FTSJNIUtils.java @@ -0,0 +1,14 @@ +package com.tencent.mm.plugin.fts.jni; + +public class FTSJNIUtils { + public static native int countTokens(String str); + + public static native int icuInitialize(String str); + + public static native String icuTokenizer(String str); + + public static native void nativeInitFts(long j, byte[] bArr); + + public static native int stringCompareUtfBinary(String str, String str2); + +} diff --git a/WXGFDecoder/app/src/main/java/com/tencent/mm/plugin/gif/MMWXGFJNI.java b/WXGFDecoder/app/src/main/java/com/tencent/mm/plugin/gif/MMWXGFJNI.java new file mode 100644 index 0000000..da82b6a --- /dev/null +++ b/WXGFDecoder/app/src/main/java/com/tencent/mm/plugin/gif/MMWXGFJNI.java @@ -0,0 +1,101 @@ +//File: +package com.tencent.mm.plugin.gif; + +import android.graphics.Bitmap; + +import java.io.File; +/* + *import com.tencent.matrix.trace.core.AppMethodBeat; + *import com.tencent.mm.loader.p558j.C11743b; + *import com.tencent.mm.sdk.platformtools.C52656ad; + */ + +/* renamed from: com.tencent.mm.plugin.gif.MMWXGFJNI */ +public class MMWXGFJNI { + public static final int PIC_TYPE_JPG = 0; + public static final int PIC_TYPE_PNG = 1; + private static final String TAG = "MicroMsg.JNI.MMWXGF"; + static int mECode; + public static boolean mIsInit; + + + public static native int nativeAV2Gif(String str, String str2); + + public static native int nativeAV2Gif(byte[] bArr, byte[] bArr2); + + public static native int nativeAddGifEncodeRgbaFrame(long j, int i, int i2, byte[] bArr, long j2); + + public static native int nativeAddWxAMEncodeRgbaFrame(long j, int i, int i2, byte[] bArr, long j2); + + public static native int nativeDecodeBufferFrame(long j, byte[] bArr, int i, Bitmap bitmap, int[] iArr); + + public static native int nativeDecodeBufferHeader(long j, byte[] bArr, int i); + + public static native byte[] nativeFinishGifEncode(long j); + + public static native byte[] nativeFinishWxAMEncode(long j); + + public static native int nativeGetOption(long j, byte[] bArr, int i, int[] iArr); + + public static native int nativeInit(String str); + + public static native long nativeInitGifEncode(int i, int i2, long j); + + public static native long nativeInitWxAMDecoder(); + + public static native long nativeInitWxAMEncoder(int i, int i2, long j, int i3); + + public static native boolean nativeIsWXGF(byte[] bArr, int i); + + public static native int nativePic2Wxam(String str, String str2, int i, int i2); + + public static native int nativePic2WxamWithWH(String str, String str2, int i, int i2, int i3, int i4); + + public static native int nativePic2WxamWithWH(String str, byte[] bArr, int i, int i2, int i3, int i4, int i5, int i6, int i7); + + public static native int nativeRewindBuffer(long j); + + public static native int nativeUninit(long j); + + public static native int nativeWxam2Pic(String str, String str2); + + public static native byte[] nativeWxam2PicBuf(byte[] bArr); + + public static native byte[] nativeWxamToGif(byte[] bArr); + + public static void initialize(String nativeDir) { + // init wxgf decoder + String soFilePath = nativeDir + "/libvoipCodec.so"; + File soFile = new File(soFilePath); + if (!soFile.exists()) + throw new RuntimeException("missing so file " + soFilePath); + int initSuccess = nativeInit(soFilePath); // return -1 if missing so + if (initSuccess < 0) + throw new RuntimeException("nativeInit failed " + initSuccess); + mIsInit = true; + } + /* // Original code below: + *static { + * AppMethodBeat.m13231i(104681); + * mIsInit = false; + * mECode = -1; + * C52656ad.m88211i(TAG, "static MMWXGFJNI"); + * if (!mIsInit) { + * String str = C11743b.ahY() + "lib/libvoipCodec.so"; + * int nativeInit = nativeInit(str); + * mECode = nativeInit; + * mIsInit = nativeInit >= 0; + * C52656ad.m88212i(TAG, "native init MMWXGF mECode:%d result:%b :%s", Integer.valueOf(mECode), Boolean.valueOf(mIsInit), str); + * AppMethodBeat.m13232o(104681); + * return; + * } + * C52656ad.m88205d(TAG, "MMWXGF has init."); + * AppMethodBeat.m13232o(104681); + *} + */ + + public static int getErrorCode() { + return mECode; + } +} + diff --git a/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libc++_shared.so b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libc++_shared.so new file mode 100644 index 0000000..878631c Binary files /dev/null and b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libc++_shared.so differ diff --git a/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libcommonimgdec.so b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libcommonimgdec.so new file mode 100644 index 0000000..6ae4e75 Binary files /dev/null and b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libcommonimgdec.so differ diff --git a/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libvoipCodec.so b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libvoipCodec.so new file mode 100644 index 0000000..337032f Binary files /dev/null and b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libvoipCodec.so differ diff --git a/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libvoipComm.so b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libvoipComm.so new file mode 100644 index 0000000..30dbcec Binary files /dev/null and b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libvoipComm.so differ diff --git a/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwcdb.so b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwcdb.so new file mode 100644 index 0000000..70927ab Binary files /dev/null and b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwcdb.so differ diff --git a/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwechatcommon.so b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwechatcommon.so new file mode 100644 index 0000000..9aa3013 Binary files /dev/null and b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwechatcommon.so differ diff --git a/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwechatxlog.so b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwechatxlog.so new file mode 100644 index 0000000..89dc809 Binary files /dev/null and b/WXGFDecoder/app/src/main/jniLibs/arm64-v8a/libwechatxlog.so differ diff --git a/WXGFDecoder/app/src/main/res/drawable/ic_dashboard_black_24dp.xml b/WXGFDecoder/app/src/main/res/drawable/ic_dashboard_black_24dp.xml new file mode 100644 index 0000000..46fc8de --- /dev/null +++ b/WXGFDecoder/app/src/main/res/drawable/ic_dashboard_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/WXGFDecoder/app/src/main/res/drawable/ic_home_black_24dp.xml b/WXGFDecoder/app/src/main/res/drawable/ic_home_black_24dp.xml new file mode 100644 index 0000000..f8bb0b5 --- /dev/null +++ b/WXGFDecoder/app/src/main/res/drawable/ic_home_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/WXGFDecoder/app/src/main/res/drawable/ic_launcher_background.xml b/WXGFDecoder/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/WXGFDecoder/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/WXGFDecoder/app/src/main/res/drawable/ic_launcher_foreground.xml b/WXGFDecoder/app/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/WXGFDecoder/app/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/WXGFDecoder/app/src/main/res/drawable/ic_notifications_black_24dp.xml b/WXGFDecoder/app/src/main/res/drawable/ic_notifications_black_24dp.xml new file mode 100644 index 0000000..78b75c3 --- /dev/null +++ b/WXGFDecoder/app/src/main/res/drawable/ic_notifications_black_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/WXGFDecoder/app/src/main/res/layout/activity_main.xml b/WXGFDecoder/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..07676af --- /dev/null +++ b/WXGFDecoder/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,88 @@ + + + + + + + + + + + + + + + + + +