mirror of https://github.com/YTVanced/VancedMicroG
166 lines
6.5 KiB
Java
166 lines
6.5 KiB
Java
/*
|
|
* Copyright 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.app.PendingIntent;
|
|
import android.content.Context;
|
|
import android.content.Intent;
|
|
import android.content.pm.ApplicationInfo;
|
|
import android.content.pm.PackageManager;
|
|
import android.content.pm.ResolveInfo;
|
|
import android.os.Bundle;
|
|
import android.os.Handler;
|
|
import android.os.Looper;
|
|
import android.os.Message;
|
|
import android.os.Messenger;
|
|
import android.util.Log;
|
|
|
|
import com.google.android.gms.iid.InstanceID;
|
|
|
|
import java.io.IOException;
|
|
import java.util.concurrent.BlockingQueue;
|
|
import java.util.concurrent.LinkedBlockingQueue;
|
|
import java.util.concurrent.TimeUnit;
|
|
import java.util.concurrent.atomic.AtomicInteger;
|
|
|
|
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
|
|
import static com.google.android.gms.gcm.GoogleCloudMessaging.ERROR_SERVICE_NOT_AVAILABLE;
|
|
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
|
|
import static org.microg.gms.common.Constants.GSF_PACKAGE_NAME;
|
|
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_GCM_SEND;
|
|
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP;
|
|
import static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;
|
|
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_UNREGISTERED;
|
|
import static org.microg.gms.gcm.GcmConstants.PERMISSION_GTALK;
|
|
import static org.microg.gms.gcm.GcmConstants.PERMISSION_RECEIVE;
|
|
|
|
public class CloudMessagingRpc {
|
|
private static final AtomicInteger messageIdCounter = new AtomicInteger(1);
|
|
private static String gcmPackageName;
|
|
|
|
private final BlockingQueue<Intent> messengerResponseQueue = new LinkedBlockingQueue<Intent>();
|
|
private final Messenger messenger = new Messenger(new Handler(Looper.getMainLooper()) {
|
|
@Override
|
|
public void handleMessage(Message msg) {
|
|
if (msg == null || !(msg.obj instanceof Intent)) {
|
|
// Invalid message -> drop
|
|
return;
|
|
}
|
|
Intent intent = (Intent) msg.obj;
|
|
if (ACTION_C2DM_REGISTRATION.equals(intent.getAction())) {
|
|
messengerResponseQueue.add(intent);
|
|
}
|
|
}
|
|
});
|
|
|
|
/**
|
|
* Due to it's nature of being a monitored reference, Intents can be used to authenticate a package source.
|
|
*/
|
|
private PendingIntent selfAuthIntent;
|
|
private Context context;
|
|
|
|
public CloudMessagingRpc(Context context) {
|
|
this.context = context;
|
|
}
|
|
|
|
public static String getGcmPackageName(Context context) {
|
|
if (gcmPackageName != null) {
|
|
return gcmPackageName;
|
|
}
|
|
PackageManager packageManager = context.getPackageManager();
|
|
for (ResolveInfo resolveInfo : packageManager.queryIntentServices(new Intent(ACTION_C2DM_REGISTER), 0)) {
|
|
if (packageManager.checkPermission(PERMISSION_RECEIVE, resolveInfo.serviceInfo.packageName) == PERMISSION_GRANTED) {
|
|
return gcmPackageName = resolveInfo.serviceInfo.packageName;
|
|
}
|
|
}
|
|
try {
|
|
ApplicationInfo appInfo = packageManager.getApplicationInfo(GMS_PACKAGE_NAME, 0);
|
|
return gcmPackageName = appInfo.packageName;
|
|
} catch (PackageManager.NameNotFoundException ignored) {
|
|
}
|
|
try {
|
|
ApplicationInfo appInfo = packageManager.getApplicationInfo(GSF_PACKAGE_NAME, 0);
|
|
return gcmPackageName = appInfo.packageName;
|
|
} catch (PackageManager.NameNotFoundException ex3) {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
public void close() {
|
|
// Cancel the authentication
|
|
if (selfAuthIntent != null) {
|
|
selfAuthIntent.cancel();
|
|
selfAuthIntent = null;
|
|
}
|
|
}
|
|
|
|
private PendingIntent getSelfAuthIntent() {
|
|
if (selfAuthIntent == null) {
|
|
Intent intent = new Intent();
|
|
intent.setPackage("com.google.example.invalidpackage");
|
|
selfAuthIntent = PendingIntent.getBroadcast(context, 0, intent, 0);
|
|
}
|
|
return selfAuthIntent;
|
|
}
|
|
|
|
public Intent sendRegisterMessageBlocking(Bundle extras) throws IOException {
|
|
sendRegisterMessage(extras);
|
|
Intent resultIntent;
|
|
try {
|
|
resultIntent = messengerResponseQueue.poll(30, TimeUnit.SECONDS);
|
|
} catch (InterruptedException e) {
|
|
throw new IOException(e.getMessage());
|
|
}
|
|
if (resultIntent == null) {
|
|
throw new IOException(ERROR_SERVICE_NOT_AVAILABLE);
|
|
}
|
|
return resultIntent;
|
|
}
|
|
|
|
private void sendRegisterMessage(Bundle extras) {
|
|
Intent intent = new Intent(ACTION_C2DM_REGISTER);
|
|
intent.setPackage(getGcmPackageName(context));
|
|
extras.putString(EXTRA_MESSAGE_ID, "google.rpc" + messageIdCounter.getAndIncrement());
|
|
intent.putExtras(extras);
|
|
intent.putExtra(EXTRA_MESSENGER, messenger);
|
|
intent.putExtra(EXTRA_APP, getSelfAuthIntent());
|
|
context.startService(intent);
|
|
}
|
|
|
|
public void sendGcmMessage(Bundle extras) {
|
|
Intent intent = new Intent(ACTION_GCM_SEND);
|
|
intent.setPackage(GMS_PACKAGE_NAME);
|
|
intent.putExtras(extras);
|
|
intent.putExtra(EXTRA_APP, getSelfAuthIntent());
|
|
context.sendOrderedBroadcast(intent, PERMISSION_GTALK);
|
|
}
|
|
|
|
public String handleRegisterMessageResult(Intent resultIntent) throws IOException {
|
|
if (resultIntent == null) throw new IOException(InstanceID.ERROR_SERVICE_NOT_AVAILABLE);
|
|
String result = resultIntent.getStringExtra(EXTRA_REGISTRATION_ID);
|
|
if (result == null) result = resultIntent.getStringExtra(EXTRA_UNREGISTERED);
|
|
if (result != null) return result;
|
|
result = resultIntent.getStringExtra(EXTRA_ERROR);
|
|
throw new IOException(result != null ? result : InstanceID.ERROR_SERVICE_NOT_AVAILABLE);
|
|
}
|
|
}
|