mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2024-11-19 02:29:25 +01:00
GCM improvements
- Add upstream message support (#228) - Improve support for 7.0+ (#226) - don't start closed apps if disabled (#230) - ask after denying registered app (#230) - automatically unregister apps on uninstall
This commit is contained in:
parent
279b35b993
commit
97f4c82172
@ -26,6 +26,10 @@
|
||||
android:name="com.google.android.c2dm.permission.SEND"
|
||||
android:label="@string/perm_c2dm_send_label"
|
||||
android:protectionLevel="signature"/>
|
||||
<permission
|
||||
android:name="com.google.android.gtalkservice.permission.GTALK_SERVICE"
|
||||
android:label="@string/perm_gtalk_svc_label"
|
||||
android:protectionLevel="signature"/>
|
||||
|
||||
<permission-tree
|
||||
android:name="com.google.android.googleapps.permission.GOOGLE_AUTH"
|
||||
@ -74,9 +78,12 @@
|
||||
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
|
||||
<uses-permission android:name="com.google.android.c2dm.permission.SEND"/>
|
||||
<uses-permission android:name="com.google.android.gtalkservice.permission.GTALK_SERVICE"/>
|
||||
|
||||
<uses-permission android:name="org.microg.gms.STATUS_BROADCAST"/>
|
||||
|
||||
<uses-permission android:name="android.permission.REQUEST_IGNORE_BATTERY_OPTIMIZATIONS"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
@ -167,8 +174,6 @@
|
||||
<receiver android:name="org.microg.gms.checkin.TriggerReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.server.checkin.CHECKIN"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
|
||||
</intent-filter>
|
||||
<intent-filter>
|
||||
@ -200,14 +205,26 @@
|
||||
<category android:name="android.intent.category.DEFAULT"/>
|
||||
</intent-filter>
|
||||
</service>
|
||||
<service
|
||||
android:name="org.microg.gms.gcm.McsService"
|
||||
android:exported="true"/>
|
||||
|
||||
<service android:name="org.microg.gms.gcm.McsService"/>
|
||||
|
||||
<receiver
|
||||
android:name="org.microg.gms.gcm.SendReceiver"
|
||||
android:permission="com.google.android.c2dm.permission.RECEIVE">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gcm.intent.SEND"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
<receiver android:name="org.microg.gms.gcm.TriggerReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.BOOT_COMPLETED"/>
|
||||
<action android:name="android.intent.action.AIRPLANE_MODE"/>
|
||||
<action android:name="android.net.conn.CONNECTIVITY_CHANGE"/>
|
||||
<action android:name="android.net.conn.BACKGROUND_DATA_SETTING_CHANGED"/>
|
||||
|
||||
<action android:name="org.microg.gms.gcm.RECONNECT"/>
|
||||
|
||||
<action android:name="android.intent.action.MY_PACKAGE_REPLACED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_RESTARTED"/>
|
||||
</intent-filter>
|
||||
@ -222,7 +239,10 @@
|
||||
|
||||
<receiver android:name="org.microg.gms.gcm.UnregisterReceiver">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.PACKAGE_ADDED"/>
|
||||
<action android:name="android.intent.action.PACKAGE_REMOVED"/>
|
||||
|
||||
<data android:scheme="package"/>
|
||||
</intent-filter>
|
||||
</receiver>
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
package org.microg.gms.common;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
@ -28,6 +29,7 @@ import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.Arrays;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
|
||||
import static org.microg.gms.common.Constants.GMS_PACKAGE_SIGNATURE_SHA1;
|
||||
|
||||
@ -95,6 +97,15 @@ public class PackageUtils {
|
||||
return null;
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public static String packageFromPendingIntent(PendingIntent pi) {
|
||||
if (SDK_INT < android.os.Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return pi.getTargetPackage();
|
||||
} else {
|
||||
return pi.getCreatorPackage();
|
||||
}
|
||||
}
|
||||
|
||||
public static String sha1sum(byte[] bytes) {
|
||||
MessageDigest md;
|
||||
try {
|
||||
|
@ -40,5 +40,6 @@ public final class McsConstants {
|
||||
public static String ACTION_CONNECT = "org.microg.gms.gcm.mcs.CONNECT";
|
||||
public static String ACTION_RECONNECT = "org.microg.gms.gcm.mcs.RECONNECT";
|
||||
public static String ACTION_HEARTBEAT = "org.microg.gms.gcm.mcs.HEARTBEAT";
|
||||
public static String ACTION_SEND = "org.microg.gms.gcm.mcs.SEND";
|
||||
public static String EXTRA_REASON = "org.microg.gms.gcm.mcs.REASON";
|
||||
}
|
||||
|
@ -147,24 +147,29 @@ public class McsInputStream extends Thread implements Closeable {
|
||||
|
||||
private static Message read(int mcsTag, byte[] bytes, int len) throws IOException {
|
||||
Wire wire = new Wire();
|
||||
switch (mcsTag) {
|
||||
case MCS_HEARTBEAT_PING_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, HeartbeatPing.class);
|
||||
case MCS_HEARTBEAT_ACK_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, HeartbeatAck.class);
|
||||
case MCS_LOGIN_REQUEST_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, LoginRequest.class);
|
||||
case MCS_LOGIN_RESPONSE_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, LoginResponse.class);
|
||||
case MCS_CLOSE_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, Close.class);
|
||||
case MCS_IQ_STANZA_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, IqStanza.class);
|
||||
case MCS_DATA_MESSAGE_STANZA_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, DataMessageStanza.class);
|
||||
default:
|
||||
Log.w(TAG, "Unknown tag: " + mcsTag);
|
||||
return null;
|
||||
try {
|
||||
switch (mcsTag) {
|
||||
case MCS_HEARTBEAT_PING_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, HeartbeatPing.class);
|
||||
case MCS_HEARTBEAT_ACK_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, HeartbeatAck.class);
|
||||
case MCS_LOGIN_REQUEST_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, LoginRequest.class);
|
||||
case MCS_LOGIN_RESPONSE_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, LoginResponse.class);
|
||||
case MCS_CLOSE_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, Close.class);
|
||||
case MCS_IQ_STANZA_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, IqStanza.class);
|
||||
case MCS_DATA_MESSAGE_STANZA_TAG:
|
||||
return wire.parseFrom(bytes, 0, len, DataMessageStanza.class);
|
||||
default:
|
||||
Log.w(TAG, "Unknown tag: " + mcsTag);
|
||||
return null;
|
||||
}
|
||||
} catch (IllegalStateException e) {
|
||||
Log.w(TAG, "Error parsing tag: "+mcsTag, e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,9 +25,12 @@ import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Looper;
|
||||
import android.os.Messenger;
|
||||
import android.os.Parcelable;
|
||||
import android.os.PowerManager;
|
||||
import android.os.SystemClock;
|
||||
import android.support.v4.content.WakefulBroadcastReceiver;
|
||||
@ -36,6 +39,7 @@ import android.util.Log;
|
||||
import com.squareup.wire.Message;
|
||||
|
||||
import org.microg.gms.checkin.LastCheckinInfo;
|
||||
import org.microg.gms.common.PackageUtils;
|
||||
import org.microg.gms.gcm.mcs.AppData;
|
||||
import org.microg.gms.gcm.mcs.Close;
|
||||
import org.microg.gms.gcm.mcs.DataMessageStanza;
|
||||
@ -47,19 +51,30 @@ import org.microg.gms.gcm.mcs.Setting;
|
||||
|
||||
import java.io.Closeable;
|
||||
import java.net.Socket;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
|
||||
import okio.ByteString;
|
||||
|
||||
import static android.app.AlarmManager.ELAPSED_REALTIME_WAKEUP;
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_COLLAPSE_KEY;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSAGE_ID;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSENGER;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_SEND_FROM;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_SEND_TO;
|
||||
import static org.microg.gms.gcm.GcmConstants.EXTRA_TTL;
|
||||
import static org.microg.gms.gcm.McsConstants.ACTION_CONNECT;
|
||||
import static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT;
|
||||
import static org.microg.gms.gcm.McsConstants.ACTION_RECONNECT;
|
||||
import static org.microg.gms.gcm.McsConstants.ACTION_SEND;
|
||||
import static org.microg.gms.gcm.McsConstants.EXTRA_REASON;
|
||||
import static org.microg.gms.gcm.McsConstants.MCS_CLOSE_TAG;
|
||||
import static org.microg.gms.gcm.McsConstants.MCS_DATA_MESSAGE_STANZA_TAG;
|
||||
@ -111,6 +126,8 @@ public class McsService extends Service implements Handler.Callback {
|
||||
|
||||
private Intent connectIntent;
|
||||
|
||||
private static int maxTtl = 24 * 60 * 60;
|
||||
|
||||
private class HandlerThread extends Thread {
|
||||
|
||||
public HandlerThread() {
|
||||
@ -140,6 +157,7 @@ public class McsService extends Service implements Handler.Callback {
|
||||
@Override
|
||||
public void onCreate() {
|
||||
super.onCreate();
|
||||
TriggerReceiver.register(this);
|
||||
database = new GcmDatabase(this);
|
||||
heartbeatIntent = PendingIntent.getService(this, 0, new Intent(ACTION_HEARTBEAT, null, this, McsService.class), 0);
|
||||
alarmManager = (AlarmManager) getSystemService(ALARM_SERVICE);
|
||||
@ -152,6 +170,12 @@ public class McsService extends Service implements Handler.Callback {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
database.close();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent intent) {
|
||||
return null;
|
||||
@ -221,6 +245,8 @@ public class McsService extends Service implements Handler.Callback {
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_CONNECT, reason));
|
||||
} else if (ACTION_HEARTBEAT.equals(intent.getAction())) {
|
||||
rootHandler.sendMessage(rootHandler.obtainMessage(MSG_HEARTBEAT, reason));
|
||||
} else if (ACTION_SEND.equals(intent.getAction())) {
|
||||
handleSendMessage(intent);
|
||||
}
|
||||
WakefulBroadcastReceiver.completeWakefulIntent(intent);
|
||||
} else if (connectIntent == null) {
|
||||
@ -232,6 +258,94 @@ public class McsService extends Service implements Handler.Callback {
|
||||
return START_REDELIVER_INTENT;
|
||||
}
|
||||
|
||||
private void handleSendMessage(Intent intent) {
|
||||
String messageId = intent.getStringExtra(EXTRA_MESSAGE_ID);
|
||||
String collapseKey = intent.getStringExtra(EXTRA_COLLAPSE_KEY);
|
||||
|
||||
Messenger messenger = intent.getParcelableExtra(EXTRA_MESSENGER);
|
||||
intent.removeExtra(EXTRA_MESSENGER);
|
||||
|
||||
Parcelable app = intent.getParcelableExtra(EXTRA_APP);
|
||||
String packageName = null;
|
||||
if (app instanceof PendingIntent) {
|
||||
packageName = PackageUtils.packageFromPendingIntent((PendingIntent) app);
|
||||
}
|
||||
if (packageName == null) {
|
||||
Log.w(TAG, "Failed to send message, missing package name");
|
||||
return;
|
||||
}
|
||||
intent.removeExtra(EXTRA_APP);
|
||||
|
||||
int ttl;
|
||||
try {
|
||||
ttl = Integer.parseInt(intent.getStringExtra(EXTRA_TTL));
|
||||
if (ttl < 0 || ttl > maxTtl) {
|
||||
ttl = maxTtl;
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// TODO: error TtlUnsupported
|
||||
Log.w(TAG, e);
|
||||
return;
|
||||
}
|
||||
|
||||
String to = intent.getStringExtra(EXTRA_SEND_TO);
|
||||
if (to == null) {
|
||||
// TODO: error missing_to
|
||||
Log.w(TAG, "missing to");
|
||||
return;
|
||||
}
|
||||
|
||||
String from = intent.getStringExtra(EXTRA_SEND_FROM);
|
||||
if (from != null) {
|
||||
intent.removeExtra(EXTRA_SEND_FROM);
|
||||
} else {
|
||||
from = intent.getStringExtra(EXTRA_FROM);
|
||||
}
|
||||
if (from == null) {
|
||||
GcmDatabase.Registration reg = database.getRegistration(packageName, PackageUtils.firstSignatureDigest(this, packageName));
|
||||
if (reg != null) from = reg.registerId;
|
||||
}
|
||||
if (from == null) {
|
||||
Log.e(TAG, "Can't send message, missing from!");
|
||||
return;
|
||||
}
|
||||
|
||||
String registrationId = intent.getStringExtra(EXTRA_REGISTRATION_ID);
|
||||
intent.removeExtra(EXTRA_REGISTRATION_ID);
|
||||
|
||||
List<AppData> appData = new ArrayList<>();
|
||||
Bundle extras = intent.getExtras();
|
||||
for (String key : extras.keySet()) {
|
||||
if (!key.startsWith("google.")) {
|
||||
Object val = extras.get(key);
|
||||
if (val instanceof String) {
|
||||
appData.add(new AppData(key, (String) val));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
byte[] rawDataArray = intent.getByteArrayExtra("rawData");
|
||||
ByteString rawData = rawDataArray != null ? ByteString.of(rawDataArray) : null;
|
||||
|
||||
try {
|
||||
DataMessageStanza msg = new DataMessageStanza.Builder()
|
||||
.sent(System.currentTimeMillis() / 1000L)
|
||||
.id(messageId)
|
||||
.token(collapseKey)
|
||||
.from(from)
|
||||
.reg_id(registrationId)
|
||||
.to(to)
|
||||
.category(packageName)
|
||||
.raw_data(rawData)
|
||||
.app_data(appData).build();
|
||||
|
||||
send(MCS_DATA_MESSAGE_STANZA_TAG, msg);
|
||||
database.noteAppMessage(packageName, msg.getSerializedSize());
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, e);
|
||||
}
|
||||
}
|
||||
|
||||
private synchronized void connect() {
|
||||
try {
|
||||
tryClose(inputStream);
|
||||
@ -319,7 +433,11 @@ public class McsService extends Service implements Handler.Callback {
|
||||
intent.setAction(ACTION_C2DM_RECEIVE);
|
||||
intent.setPackage(msg.category);
|
||||
intent.putExtra(EXTRA_FROM, msg.from);
|
||||
if (app.wakeForDelivery) intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
if (app.wakeForDelivery) {
|
||||
intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES);
|
||||
} else {
|
||||
intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES);
|
||||
}
|
||||
if (msg.token != null) intent.putExtra(EXTRA_COLLAPSE_KEY, msg.token);
|
||||
for (AppData appData : msg.app_data) {
|
||||
intent.putExtra(appData.key, appData.value);
|
||||
|
@ -16,18 +16,14 @@
|
||||
|
||||
package org.microg.gms.gcm;
|
||||
|
||||
import android.app.AlertDialog;
|
||||
import android.app.IntentService;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.ApplicationInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.os.Build;
|
||||
import android.os.Message;
|
||||
import android.os.Messenger;
|
||||
import android.text.Html;
|
||||
import android.util.Log;
|
||||
|
||||
import org.microg.gms.checkin.CheckinService;
|
||||
@ -38,10 +34,6 @@ import org.microg.gms.ui.AskPushPermission;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.os.Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||
import static android.os.Build.VERSION_CODES.JELLY_BEAN;
|
||||
import static android.os.Build.VERSION_CODES.JELLY_BEAN_MR1;
|
||||
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTER;
|
||||
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;
|
||||
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_UNREGISTER;
|
||||
@ -74,6 +66,12 @@ public class PushRegisterService extends IntentService {
|
||||
database = new GcmDatabase(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
database.close();
|
||||
}
|
||||
|
||||
public static RegisterResponse register(Context context, String packageName, String pkgSignature, String sender, String info) {
|
||||
GcmDatabase database = new GcmDatabase(context);
|
||||
RegisterResponse response = register(context, packageName, pkgSignature, sender, info, false);
|
||||
@ -83,6 +81,7 @@ public class PushRegisterService extends IntentService {
|
||||
} else {
|
||||
database.noteAppRegistrationError(packageName, response.responseText);
|
||||
}
|
||||
database.close();
|
||||
return response;
|
||||
}
|
||||
|
||||
@ -94,12 +93,14 @@ public class PushRegisterService extends IntentService {
|
||||
} else {
|
||||
database.noteAppUnregistered(packageName, pkgSignature);
|
||||
}
|
||||
database.close();
|
||||
return response;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHandleIntent(Intent intent) {
|
||||
Log.d(TAG, "onHandleIntent: " + intent);
|
||||
Log.d(TAG, "onHandleIntent: " + intent.getExtras());
|
||||
if (LastCheckinInfo.read(this).lastCheckin > 0) {
|
||||
try {
|
||||
if (ACTION_C2DM_UNREGISTER.equals(intent.getAction()) ||
|
||||
@ -121,18 +122,9 @@ public class PushRegisterService extends IntentService {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
private String packageFromPendingIntent(PendingIntent pi) {
|
||||
if (SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
|
||||
return pi.getTargetPackage();
|
||||
} else {
|
||||
return pi.getCreatorPackage();
|
||||
}
|
||||
}
|
||||
|
||||
private void register(final Intent intent) {
|
||||
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_APP);
|
||||
final String packageName = packageFromPendingIntent(pendingIntent);
|
||||
final String packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
|
||||
Log.d(TAG, "register[req]: " + intent.toString() + " extras=" + intent.getExtras());
|
||||
|
||||
GcmDatabase.App app = database.getApp(packageName);
|
||||
@ -214,7 +206,7 @@ public class PushRegisterService extends IntentService {
|
||||
|
||||
private void unregister(Intent intent) {
|
||||
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_APP);
|
||||
String packageName = packageFromPendingIntent(pendingIntent);
|
||||
String packageName = PackageUtils.packageFromPendingIntent(pendingIntent);
|
||||
Log.d(TAG, "unregister[req]: " + intent.toString() + " extras=" + intent.getExtras());
|
||||
|
||||
Intent outIntent = new Intent(ACTION_C2DM_REGISTRATION);
|
||||
|
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2013-2016 microG Project Team
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.microg.gms.gcm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.content.WakefulBroadcastReceiver;
|
||||
import android.util.Log;
|
||||
|
||||
import static org.microg.gms.gcm.McsConstants.ACTION_SEND;
|
||||
|
||||
public class SendReceiver extends WakefulBroadcastReceiver {
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
if (intent.getExtras() == null) return;
|
||||
Bundle extras = intent.getExtras();
|
||||
Log.d("GmsMcsSendRcvr", "original extras: " + extras);
|
||||
for (String key : extras.keySet()) {
|
||||
if (key.startsWith("GOOG.") || key.startsWith("GOOGLE.")) {
|
||||
extras.remove(key);
|
||||
}
|
||||
}
|
||||
Intent i = new Intent(context, McsService.class);
|
||||
i.setAction(ACTION_SEND);
|
||||
i.putExtras(extras);
|
||||
startWakefulService(context, i);
|
||||
}
|
||||
}
|
@ -18,20 +18,35 @@ package org.microg.gms.gcm;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentFilter;
|
||||
import android.net.ConnectivityManager;
|
||||
import android.net.NetworkInfo;
|
||||
import android.preference.PreferenceManager;
|
||||
import android.support.v4.content.WakefulBroadcastReceiver;
|
||||
import android.util.Log;
|
||||
|
||||
import org.microg.gms.checkin.LastCheckinInfo;
|
||||
|
||||
import static android.os.Build.VERSION.SDK_INT;
|
||||
import static android.os.Build.VERSION_CODES.N;
|
||||
import static org.microg.gms.gcm.McsConstants.ACTION_CONNECT;
|
||||
import static org.microg.gms.gcm.McsConstants.ACTION_HEARTBEAT;
|
||||
import static org.microg.gms.gcm.McsConstants.EXTRA_REASON;
|
||||
|
||||
public class TriggerReceiver extends WakefulBroadcastReceiver {
|
||||
private static final String TAG = "GmsGcmTrigger";
|
||||
private static boolean registered = false;
|
||||
|
||||
/**
|
||||
* "Project Svelte" is just there to f**k things up...
|
||||
*/
|
||||
public synchronized static void register(Context context) {
|
||||
if (SDK_INT >= N && !registered) {
|
||||
IntentFilter intentFilter = new IntentFilter("android.net.conn.CONNECTIVITY_CHANGE");
|
||||
context.registerReceiver(new TriggerReceiver(), intentFilter);
|
||||
registered = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
@ -48,9 +63,9 @@ public class TriggerReceiver extends WakefulBroadcastReceiver {
|
||||
}
|
||||
|
||||
NetworkInfo networkInfo = cm.getActiveNetworkInfo();
|
||||
if (networkInfo != null && networkInfo.isConnected() || force) {
|
||||
if (networkInfo != null && networkInfo.isConnected() || force || "android.intent.action.BOOT_COMPLETED".equals(intent.getAction())) {
|
||||
if (!McsService.isConnected() || force) {
|
||||
Log.d(TAG, "Not connected to GCM but should be, asking the service to start up");
|
||||
Log.d(TAG, "Not connected to GCM but should be, asking the service to start up. Triggered by: " + intent);
|
||||
startWakefulService(context, new Intent(ACTION_CONNECT, null, context, McsService.class)
|
||||
.putExtra(EXTRA_REASON, intent));
|
||||
} else {
|
||||
|
@ -5,6 +5,8 @@ import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.util.Log;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static android.content.Intent.ACTION_PACKAGE_REMOVED;
|
||||
import static android.content.Intent.EXTRA_DATA_REMOVED;
|
||||
|
||||
@ -12,10 +14,31 @@ public class UnregisterReceiver extends BroadcastReceiver {
|
||||
private static final String TAG = "GmsGcmUnregisterRcvr";
|
||||
|
||||
@Override
|
||||
public void onReceive(Context context, Intent intent) {
|
||||
Log.d(TAG, "Package removed: " + intent);
|
||||
public void onReceive(final Context context, Intent intent) {
|
||||
Log.d(TAG, "Package changed: " + intent);
|
||||
if (ACTION_PACKAGE_REMOVED.contains(intent.getAction()) && intent.getBooleanExtra(EXTRA_DATA_REMOVED, false)) {
|
||||
Log.d(TAG, "Package removed: " + intent.getData());
|
||||
final GcmDatabase database = new GcmDatabase(context);
|
||||
final String packageName = intent.getData().getSchemeSpecificPart();
|
||||
Log.d(TAG, "Package removed: " + packageName);
|
||||
final GcmDatabase.App app = database.getApp(packageName);
|
||||
if (app != null) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
List<GcmDatabase.Registration> registrations = database.getRegistrationsByApp(packageName);
|
||||
boolean deletedAll = true;
|
||||
for (GcmDatabase.Registration registration : registrations) {
|
||||
deletedAll &= PushRegisterService.unregister(context, registration.packageName, registration.signature, null, null).deleted != null;
|
||||
}
|
||||
if (deletedAll) {
|
||||
database.removeApp(packageName);
|
||||
}
|
||||
database.close();
|
||||
}
|
||||
}).start();
|
||||
} else {
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -84,5 +84,6 @@ public class AskPushPermission extends FragmentActivity {
|
||||
PushRegisterService.replyNotAvailable(AskPushPermission.this, intent, packageName);
|
||||
answered = true;
|
||||
}
|
||||
database.close();
|
||||
}
|
||||
}
|
||||
|
@ -82,6 +82,12 @@ public class GcmAppFragment extends ResourceSettingsFragment {
|
||||
updateAppDetails();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPause() {
|
||||
super.onPause();
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
@ -113,6 +119,39 @@ public class GcmAppFragment extends ResourceSettingsFragment {
|
||||
@Override
|
||||
public boolean onPreferenceChange(Preference preference, Object newValue) {
|
||||
if (newValue instanceof Boolean) {
|
||||
if (!(boolean) newValue) {
|
||||
final List<GcmDatabase.Registration> registrations = database.getRegistrationsByApp(packageName);
|
||||
if (!registrations.isEmpty()) {
|
||||
new AlertDialog.Builder(getContext())
|
||||
.setTitle(String.format(getString(R.string.gcm_unregister_confirm_title), appName))
|
||||
.setMessage(R.string.gcm_unregister_after_deny_message)
|
||||
.setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
new Thread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
for (GcmDatabase.Registration registration : registrations) {
|
||||
PushRegisterService.unregister(getContext(), registration.packageName, registration.signature, null, null);
|
||||
}
|
||||
getActivity().runOnUiThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
updateAppDetails();
|
||||
}
|
||||
});
|
||||
}
|
||||
}).start();
|
||||
}
|
||||
})
|
||||
.setNegativeButton(android.R.string.no, new DialogInterface.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Do nothing
|
||||
}
|
||||
}).show();
|
||||
}
|
||||
}
|
||||
database.setAppAllowRegister(packageName, (Boolean) newValue);
|
||||
return true;
|
||||
}
|
||||
@ -169,7 +208,7 @@ public class GcmAppFragment extends ResourceSettingsFragment {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
// Do nothing
|
||||
}
|
||||
}).create().show();
|
||||
}).show();
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
@ -115,6 +115,7 @@ public class GcmFragment extends ResourceSettingsFragment implements SwitchBar.O
|
||||
listenerSetup = false;
|
||||
}
|
||||
super.onPause();
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -225,6 +226,7 @@ public class GcmFragment extends ResourceSettingsFragment implements SwitchBar.O
|
||||
} else {
|
||||
setSummary(R.string.gcm_no_message_yet);
|
||||
}
|
||||
database.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -56,7 +56,9 @@ public class SettingsActivity extends AbstractDashboardActivity {
|
||||
PreferenceManager prefs = getPreferenceManager();
|
||||
prefs.findPreference(PREF_ABOUT).setSummary(getString(R.string.about_version_str, AboutFragment.getSelfVersion(getContext())));
|
||||
if (GcmPrefs.get(getContext()).isGcmEnabled()) {
|
||||
int regCount = new GcmDatabase(getContext()).getRegistrationList().size();
|
||||
GcmDatabase database = new GcmDatabase(getContext());
|
||||
int regCount = database.getRegistrationList().size();
|
||||
database.close();
|
||||
prefs.findPreference(PREF_GCM).setSummary(getString(R.string.v7_preference_on) + " / " + getContext().getString(R.string.gcm_registered_apps_counter, regCount));
|
||||
} else {
|
||||
prefs.findPreference(PREF_GCM).setSummary(R.string.v7_preference_off);
|
||||
|
@ -6,8 +6,10 @@ import com.squareup.wire.Message;
|
||||
import com.squareup.wire.ProtoField;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import okio.ByteString;
|
||||
|
||||
import static com.squareup.wire.Message.Datatype.BOOL;
|
||||
import static com.squareup.wire.Message.Datatype.BYTES;
|
||||
import static com.squareup.wire.Message.Datatype.INT32;
|
||||
import static com.squareup.wire.Message.Datatype.INT64;
|
||||
import static com.squareup.wire.Message.Datatype.STRING;
|
||||
@ -39,6 +41,8 @@ public final class DataMessageStanza extends Message {
|
||||
public static final Long DEFAULT_SENT = 0L;
|
||||
public static final Integer DEFAULT_QUEUED = 0;
|
||||
public static final Long DEFAULT_STATUS = 0L;
|
||||
public static final ByteString DEFAULT_RAW_DATA = ByteString.EMPTY;
|
||||
public static final Integer DEFAULT_DELAY = 0;
|
||||
|
||||
/**
|
||||
* Not used.
|
||||
@ -159,7 +163,13 @@ public final class DataMessageStanza extends Message {
|
||||
@ProtoField(tag = 20, type = INT64)
|
||||
public final Long status;
|
||||
|
||||
public DataMessageStanza(Long rmq_id, String id, String from, String to, String category, String token, List<AppData> app_data, Boolean from_trusted_server, String persistent_id, Integer stream_id, Integer last_stream_id_received, String permission, String reg_id, String pkg_signature, String client_id, Long device_user_id, Integer ttl, Long sent, Integer queued, Long status) {
|
||||
@ProtoField(tag = 21, type = BYTES)
|
||||
public final ByteString raw_data;
|
||||
|
||||
@ProtoField(tag = 22, type = INT32)
|
||||
public final Integer delay;
|
||||
|
||||
public DataMessageStanza(Long rmq_id, String id, String from, String to, String category, String token, List<AppData> app_data, Boolean from_trusted_server, String persistent_id, Integer stream_id, Integer last_stream_id_received, String permission, String reg_id, String pkg_signature, String client_id, Long device_user_id, Integer ttl, Long sent, Integer queued, Long status, ByteString raw_data, Integer delay) {
|
||||
this.rmq_id = rmq_id;
|
||||
this.id = id;
|
||||
this.from = from;
|
||||
@ -180,10 +190,12 @@ public final class DataMessageStanza extends Message {
|
||||
this.sent = sent;
|
||||
this.queued = queued;
|
||||
this.status = status;
|
||||
this.raw_data = raw_data;
|
||||
this.delay = delay;
|
||||
}
|
||||
|
||||
private DataMessageStanza(Builder builder) {
|
||||
this(builder.rmq_id, builder.id, builder.from, builder.to, builder.category, builder.token, builder.app_data, builder.from_trusted_server, builder.persistent_id, builder.stream_id, builder.last_stream_id_received, builder.permission, builder.reg_id, builder.pkg_signature, builder.client_id, builder.device_user_id, builder.ttl, builder.sent, builder.queued, builder.status);
|
||||
this(builder.rmq_id, builder.id, builder.from, builder.to, builder.category, builder.token, builder.app_data, builder.from_trusted_server, builder.persistent_id, builder.stream_id, builder.last_stream_id_received, builder.permission, builder.reg_id, builder.pkg_signature, builder.client_id, builder.device_user_id, builder.ttl, builder.sent, builder.queued, builder.status, builder.raw_data, builder.delay);
|
||||
setBuilder(builder);
|
||||
}
|
||||
|
||||
@ -211,7 +223,9 @@ public final class DataMessageStanza extends Message {
|
||||
&& equals(ttl, o.ttl)
|
||||
&& equals(sent, o.sent)
|
||||
&& equals(queued, o.queued)
|
||||
&& equals(status, o.status);
|
||||
&& equals(status, o.status)
|
||||
&& equals(raw_data, o.raw_data)
|
||||
&& equals(delay, o.delay);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -238,6 +252,8 @@ public final class DataMessageStanza extends Message {
|
||||
result = result * 37 + (sent != null ? sent.hashCode() : 0);
|
||||
result = result * 37 + (queued != null ? queued.hashCode() : 0);
|
||||
result = result * 37 + (status != null ? status.hashCode() : 0);
|
||||
result = result * 37 + (raw_data != null ? raw_data.hashCode() : 0);
|
||||
result = result * 37 + (delay != null ? delay.hashCode() : 0);
|
||||
hashCode = result;
|
||||
}
|
||||
return result;
|
||||
@ -265,6 +281,8 @@ public final class DataMessageStanza extends Message {
|
||||
public Long sent;
|
||||
public Integer queued;
|
||||
public Long status;
|
||||
public ByteString raw_data;
|
||||
public Integer delay;
|
||||
|
||||
public Builder() {
|
||||
}
|
||||
@ -292,6 +310,8 @@ public final class DataMessageStanza extends Message {
|
||||
this.sent = message.sent;
|
||||
this.queued = message.queued;
|
||||
this.status = message.status;
|
||||
this.raw_data = message.raw_data;
|
||||
this.delay = message.delay;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -453,6 +473,16 @@ public final class DataMessageStanza extends Message {
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder raw_data(ByteString raw_data) {
|
||||
this.raw_data = raw_data;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder delay(Integer delay) {
|
||||
this.delay = delay;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataMessageStanza build() {
|
||||
checkRequiredFields();
|
||||
|
@ -247,6 +247,10 @@ message DataMessageStanza {
|
||||
optional int32 queued = 19;
|
||||
|
||||
optional int64 status = 20;
|
||||
|
||||
optional bytes raw_data = 21;
|
||||
|
||||
optional int32 delay = 22;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,6 +42,7 @@ This can take a couple of minutes."</string>
|
||||
<string name="perm_status_broadcast_label">listen to internal status broadcasts</string>
|
||||
<string name="perm_c2dm_receive_label">listen to C2DM messages</string>
|
||||
<string name="perm_c2dm_send_label">send C2DM messages to other apps</string>
|
||||
<string name="perm_gtalk_svc_label">exchange messages and receive sync notifications from Google servers</string>
|
||||
|
||||
<string name="pref_auth_trust_google_title">Trust Google for app permissions</string>
|
||||
<string name="pref_auth_trust_google_summary">When disabled, the user is asked before an apps authorization request is sent to Google. Some applications will fail to use the Google account if this is disabled.</string>
|
||||
@ -118,6 +119,7 @@ This can take a couple of minutes."</string>
|
||||
<string name="gcm_registered_since">Registered since: <xliff:g example="Yesterday, 02:20 PM">%1$s</xliff:g></string>
|
||||
<string name="gcm_unregister_confirm_title">Unregister <xliff:g example="F-Droid">%1$s</xliff:g>?</string>
|
||||
<string name="gcm_unregister_confirm_message">Some apps do not automatically re-register and/or do not provide an option to do so manually. These apps might not work correctly after unregistering.\nContinue?</string>
|
||||
<string name="gcm_unregister_after_deny_message">You denied an app to register for push notifications that is already registered.\nDo you want to unregister it now so it does not receive push messages in the future?</string>
|
||||
<string name="gcm_messages_counter">Messages: <xliff:g example="123">%1$d</xliff:g> (<xliff:g example="12345">%2$d</xliff:g> bytes)</string>
|
||||
<string name="gcm_state_disconnected">Current State: Disconnected</string>
|
||||
<string name="gcm_state_connected">Current State: Connected since <xliff:g example="2 hours ago">%1$s</xliff:g></string>
|
||||
@ -136,6 +138,4 @@ This can take a couple of minutes."</string>
|
||||
<string name="network_type_wifi">Wi-Fi</string>
|
||||
<string name="network_type_roaming">Roaming</string>
|
||||
<string name="network_type_other">Other networks</string>
|
||||
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user