Skip to content

Instantly share code, notes, and snippets.

@hj91
Created February 28, 2016 13:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save hj91/e7010ce375675086f2fc to your computer and use it in GitHub Desktop.
Save hj91/e7010ce375675086f2fc to your computer and use it in GitHub Desktop.
/*
LinConnect: Mirror Android notifications on Linux Desktop
Copyright (C) 2013 Will Hauck
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package com.harshad.linconnectclient;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.ConnectivityManager;
import android.net.NetworkInfo;
import android.os.Build;
import android.os.Bundle;
import android.os.Environment;
import android.preference.PreferenceManager;
import android.util.Base64;
import android.widget.RemoteViews;
import org.apache.http.HttpResponse;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.mime.HttpMultipartMode;
import org.apache.http.entity.mime.MultipartEntity;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.util.EntityUtils;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.util.ArrayList;
@SuppressWarnings("deprecation")
public class NotificationUtilities {
public static boolean sendData(Context c, Notification n, String packageName) {
SharedPreferences prefs = PreferenceManager
.getDefaultSharedPreferences(c);
ConnectivityManager connManager = (ConnectivityManager) c
.getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo mWifi = connManager
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE); //changed on 28-12-2015
// Check Wifi state, whether notifications are enabled globally, and
// whether notifications are enabled for specific application
if (prefs.getBoolean("pref_toggle", true)
&& prefs.getBoolean(packageName, true) && mWifi.isConnected()) {
String ip = prefs.getString("pref_ip", "0.0.0.0:9090");
// Magically extract text from notification
ArrayList<String> notificationData = NotificationUtilities
.getNotificationText(n);
// Use PackageManager to get application name and icon
final PackageManager pm = c.getPackageManager();
ApplicationInfo ai;
try {
ai = pm.getApplicationInfo(packageName, 0);
} catch (final NameNotFoundException e) {
ai = null;
}
String notificationBody = "";
String notificationHeader = "";
// Create header and body of notification
if (notificationData.size() > 0) {
notificationHeader = notificationData.get(0);
if (notificationData.size() > 1) {
notificationBody = notificationData.get(1);
}
} else {
return false;
}
for (int i = 2; i < notificationData.size(); i++) {
notificationBody += "\n" + notificationData.get(i);
}
// Append application name to body
if (pm.getApplicationLabel(ai) != null) {
if (notificationBody.isEmpty()) {
notificationBody = "via " + pm.getApplicationLabel(ai);
} else {
notificationBody += " (via " + pm.getApplicationLabel(ai) + ")";
}
}
// Setup HTTP request
MultipartEntity entity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
// If the notification contains an icon, use it
if (n.largeIcon != null) {
entity.addPart(
"notificon",
new InputStreamBody(ImageUtilities
.bitmapToInputStream(n.largeIcon),
"drawable.png"
)
);
}
// Otherwise, use the application's icon
else {
entity.addPart(
"notificon",
new InputStreamBody(ImageUtilities
.bitmapToInputStream(ImageUtilities
.drawableToBitmap(pm
.getApplicationIcon(ai))),
"drawable.png"
)
);
}
HttpPost post = new HttpPost("http://" + ip + "/notif");
post.setEntity(entity);
try {
post.addHeader("notifheader", Base64.encodeToString(notificationHeader.getBytes("UTF-8"), Base64.URL_SAFE|Base64.NO_WRAP));
post.addHeader("notifdescription", Base64.encodeToString(notificationBody.getBytes("UTF-8"), Base64.URL_SAFE|Base64.NO_WRAP));
appendLog(notificationBody.getBytes("UTF-8").toString()+notificationHeader.getBytes("UTF-8").toString());
} catch (UnsupportedEncodingException e) {
post.addHeader("notifheader", Base64.encodeToString(notificationHeader.getBytes(), Base64.URL_SAFE|Base64.NO_WRAP));
post.addHeader("notifdescription", Base64.encodeToString(notificationBody.getBytes(), Base64.URL_SAFE|Base64.NO_WRAP));
}
// Send HTTP request
HttpClient client = new DefaultHttpClient();
HttpResponse response;
try {
response = client.execute(post);
String html = EntityUtils.toString(response.getEntity());
if (html.contains("true")) {
return true;
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
return false;
}
public static void appendLog(String text)
{
File externalStorageDir = Environment.getExternalStorageDirectory();
File logFile = new File(externalStorageDir , "linconnect.txt");
if (!logFile.exists())
{
try
{
logFile.createNewFile();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
try
{
//BufferedWriter for performance, true to set append to file flag
BufferedWriter buf = new BufferedWriter(new FileWriter(logFile, true));
buf.append(text);
buf.newLine();
buf.close();
}
catch (IOException e)
{
// TODO Auto-generated catch block
e.printStackTrace();
}
}
@SuppressLint({ "DefaultLocale", "NewApi" })
public static ArrayList<String> getNotificationText(
Notification notification) {
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
Bundle extras = notification.extras;
ArrayList<String> notificationData = new ArrayList<String>();
if (extras.get("android.title") != null) notificationData.add(extras.get("android.title").toString());
if (extras.get("android.text") != null) notificationData.add(extras.get("android.text").toString());
if (extras.get("android.subText") != null) notificationData.add(extras.get("android.subText").toString());
appendLog(notificationData.toString());
return notificationData;
}
else {
RemoteViews views = notification.contentView;
Class<?> secretClass = views.getClass();
try {
ArrayList<String> notificationData = new ArrayList<String>();
Field outerFields[] = secretClass.getDeclaredFields();
for (int i = 0; i < outerFields.length; i++) {
if (!outerFields[i].getName().equals("mActions"))
continue;
outerFields[i].setAccessible(true);
@SuppressWarnings("unchecked")
ArrayList<Object> actions = (ArrayList<Object>) outerFields[i]
.get(views);
for (Object action : actions) {
Field innerFields[] = action.getClass().getDeclaredFields();
Object value = null;
for (Field field : innerFields) {
field.setAccessible(true);
// Value field could possibly contain text
if (field.getName().equals("value")) {
value = field.get(action);
}
}
// Check if value is a String
if (value != null
&& value.getClass().getName().toUpperCase()
.contains("STRING")) {
notificationData.add(value.toString());
}
}
return notificationData;
}
} catch (Exception e) {
e.printStackTrace();
}
}
return null;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment