Repo cloned

This commit is contained in:
Fr4nz D13trich 2025-12-29 13:18:34 +01:00
commit 496ae75f58
7988 changed files with 1451097 additions and 0 deletions

View file

@ -0,0 +1,26 @@
plugins {
id("signal-library")
}
android {
namespace = "com.google.android.gms.cloudmessaging"
buildFeatures {
buildConfig = true
}
defaultConfig {
buildConfigField("boolean", "NOTIFICATION_PAYLOAD_ENABLED", "false")
}
lint {
disable += setOf("LogNotSignal")
}
}
dependencies {
api(project(":core-gms:base"))
api(project(":core-gms:safeparcel"))
api(project(":core-gms:tasks"))
annotationProcessor(project(":core-gms:safeparcel-processor"))
}

View file

@ -0,0 +1,204 @@
package com.google.android.gms.cloudmessaging;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import android.util.Log;
import androidx.annotation.IntDef;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.collection.ArrayMap;
import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
import com.google.android.gms.common.internal.safeparcel.SafeParcelable.Class;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.Map;
@Keep
@Class(creator = "CloudMessageCreator")
public final class CloudMessage extends AbstractSafeParcelable {
private static final String TAG = "CloudMessage";
public static final int PRIORITY_UNKNOWN = 0;
public static final int PRIORITY_HIGH = 1;
public static final int PRIORITY_NORMAL = 2;
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = {
PRIORITY_UNKNOWN,
PRIORITY_HIGH,
PRIORITY_NORMAL,
})
public @interface MessagePriority {
}
public static final Parcelable.Creator<CloudMessage> CREATOR = new CloudMessageCreator();
@Field(id = 1) final Intent intent;
private Map<String, String> dataCache;
@Constructor
public CloudMessage(@NonNull @Param(id = 1) Intent intent) {
this.intent = intent;
}
@Nullable
public String getCollapseKey() {
return intent.getStringExtra("collapse_key");
}
@NonNull
public synchronized Map<String, String> getData() {
if (dataCache == null) {
dataCache = parseExtrasToMap(intent.getExtras());
}
return dataCache;
}
@Nullable
public String getFrom() {
return intent.getStringExtra("from");
}
@NonNull
public Intent getIntent() {
return intent;
}
@Nullable
public String getMessageId() {
String msgId = intent.getStringExtra("google.message_id");
return msgId == null ? intent.getStringExtra("message_id") : msgId;
}
@Nullable
public String getMessageType() {
return intent.getStringExtra("message_type");
}
@MessagePriority
public int getOriginalPriority() {
String p = intent.getStringExtra("google.original_priority");
if (p == null) {
p = intent.getStringExtra("google.priority");
}
return parsePriority(p);
}
@MessagePriority
public int getPriority() {
String p = intent.getStringExtra("google.delivered_priority");
if (p == null) {
if ("1".equals(intent.getStringExtra("google.priority_reduced"))) {
return PRIORITY_NORMAL;
}
p = intent.getStringExtra("google.priority");
}
return parsePriority(p);
}
@Nullable
public byte[] getRawData() {
return intent.getByteArrayExtra("rawData");
}
@Nullable
public String getSenderId() {
return intent.getStringExtra("google.c.sender.id");
}
public long getSentTime() {
Bundle extras = intent.getExtras();
if (extras == null) {
return 0;
}
Object raw = extras.get("google.sent_time");
if (raw instanceof Long) {
return (Long) raw;
}
if (raw instanceof String) {
try {
return Long.parseLong((String) raw);
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid sent time: " + raw);
}
}
return 0;
}
@Nullable
public String getTo() {
return intent.getStringExtra("google.to");
}
public int getTtl() {
Bundle extras = intent.getExtras();
if (extras == null) {
return 0;
}
Object raw = extras.get("google.ttl");
if (raw instanceof Integer) {
return (Integer) raw;
}
if (raw instanceof String) {
try {
return Integer.parseInt((String) raw);
} catch (NumberFormatException e) {
Log.w(TAG, "Invalid TTL: " + raw);
}
}
return 0;
}
@Nullable
Integer getProductId() {
if (!intent.hasExtra("google.product_id")) {
return null;
}
return intent.getIntExtra("google.product_id", 0);
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
CloudMessageCreator.writeToParcel(this, dest, flags);
}
@MessagePriority
private static int parsePriority(@Nullable String p) {
if ("high".equals(p)) {
return PRIORITY_HIGH;
} else if ("normal".equals(p)) {
return PRIORITY_NORMAL;
} else {
return PRIORITY_UNKNOWN;
}
}
@NonNull
private static Map<String, String> parseExtrasToMap(@Nullable Bundle extras) {
ArrayMap<String, String> map = new ArrayMap<>();
if (extras == null) {
return map;
}
for (String key : extras.keySet()) {
Object value = extras.get(key);
if (!(value instanceof String)
|| key.startsWith("google.")
|| key.equals("from")
|| key.equals("message_type")
|| key.equals("collapse_key"))
{
continue;
}
map.put(key, (String) value);
}
return map;
}
}

View file

@ -0,0 +1,23 @@
package com.google.android.gms.cloudmessaging;
import android.os.Bundle;
import androidx.annotation.NonNull;
public class CloudMessageBundle {
private CloudMessageBundle() {}
@NonNull
public static Bundle forMessage(@NonNull CloudMessage message) {
Bundle bundle = new Bundle();
bundle.putString("google.message_id", message.getMessageId());
Integer productId = message.getProductId();
if (productId != null) {
bundle.putInt("google.product_id", productId);
}
return bundle;
}
}

View file

@ -0,0 +1,14 @@
package com.google.android.gms.cloudmessaging;
import androidx.annotation.Nullable;
final class CloudMessagingException extends Exception {
public CloudMessagingException(@Nullable String message, @Nullable Throwable cause) {
super(message, cause);
}
public CloudMessagingException(@Nullable String message) {
super(message);
}
}

View file

@ -0,0 +1,173 @@
package com.google.android.gms.cloudmessaging;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.WorkerThread;
import com.google.android.gms.common.util.concurrent.NamedThreadFactory;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.Executor;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
@Keep
public abstract class CloudMessagingReceiver extends BroadcastReceiver {
private static final String TAG = "CloudMessagingReceiver";
public static final class IntentActionKeys {
private static final String NOTIFICATION_OPEN = "com.google.firebase.messaging.NOTIFICATION_OPEN";
private static final String NOTIFICATION_DISMISS = "com.google.firebase.messaging.NOTIFICATION_DISMISS";
}
public static final class IntentKeys {
private static final String PENDING_INTENT = "pending_intent";
private static final String WRAPPED_INTENT = "wrapped_intent";
}
private static ThreadPoolExecutor singleThreadExecutor(String threadName) {
return new ThreadPoolExecutor(
0, 1, 30, TimeUnit.SECONDS,
new LinkedBlockingQueue<>(),
new NamedThreadFactory(threadName)
);
}
private static final class ExecutorsHolder {
static final ThreadPoolExecutor dispatchExecutor
= singleThreadExecutor("firebase-iid-executor");
static final ThreadPoolExecutor ackExecutor
= singleThreadExecutor("pscm-ack-executor");
}
@Override
public final void onReceive(Context context, Intent intent) {
if (intent != null) {
BroadcastReceiver.PendingResult pendingResult = goAsync();
getBroadcastExecutor().execute(
() -> handleIntent(intent, context, isOrderedBroadcast(), pendingResult)
);
}
}
@NonNull
protected Executor getBroadcastExecutor() {
return ExecutorsHolder.dispatchExecutor;
}
@NonNull
private Executor getAckExecutor() {
return ExecutorsHolder.ackExecutor;
}
@WorkerThread
protected abstract int onMessageReceive(@NonNull Context context, @NonNull CloudMessage message);
@WorkerThread
protected void onNotificationDismissed(@NonNull Context context, @NonNull Bundle data) {}
@WorkerThread
private void handleIntent(@NonNull Intent intent,
@NonNull Context context,
boolean isOrdered,
BroadcastReceiver.PendingResult pendingResult)
{
int resultCode = 500;
Parcelable wrappedIntent = intent.getParcelableExtra(IntentKeys.WRAPPED_INTENT);
try {
if (wrappedIntent instanceof Intent) {
if (BuildConfig.NOTIFICATION_PAYLOAD_ENABLED) {
resultCode = deliverDismissNotificationAction((Intent) wrappedIntent, context);
}
} else {
if (intent.getExtras() != null) {
resultCode = deliverCloudMessage(intent, context);
}
}
} finally {
if (pendingResult != null) {
if (isOrdered) {
pendingResult.setResultCode(resultCode);
}
pendingResult.finish();
}
}
}
@WorkerThread
private int deliverCloudMessage(@NonNull Intent intent, @NonNull Context context) {
CloudMessage message = new CloudMessage(intent);
CountDownLatch ackLatch = new CountDownLatch(1);
getAckExecutor().execute(() -> {
if (TextUtils.isEmpty(message.getMessageId())) {
ackLatch.countDown();
return;
}
Bundle data = CloudMessageBundle.forMessage(message);
data.putBoolean("supports_message_handled", true);
MessengerIpcClient
.getInstance(context)
.sendOneWay(GmsOpCode.BROADCAST_ACK, data)
.addOnCompleteListener(
Runnable::run, t -> ackLatch.countDown()
);
});
int result = onMessageReceive(context, message);
try {
boolean acked = ackLatch.await(1, TimeUnit.SECONDS);
if (!acked) {
Log.w(TAG, "Message ack timed out");
}
} catch (InterruptedException e) {
Log.w(TAG, "Message ack failed: " + e);
Thread.currentThread().interrupt();
}
return result;
}
@WorkerThread
private int deliverDismissNotificationAction(@NonNull Intent intent, @NonNull Context context) {
PendingIntent pendingIntent = intent.getParcelableExtra(IntentKeys.PENDING_INTENT);
if (pendingIntent != null) {
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
Log.e(TAG, "Notification pending intent canceled");
}
}
if (!IntentActionKeys.NOTIFICATION_DISMISS.equals(intent.getAction())) {
return 500;
}
Bundle extras = intent.getExtras();
if (extras != null) {
extras.remove(IntentKeys.PENDING_INTENT);
} else {
extras = new Bundle();
}
onNotificationDismissed(context, extras);
return -1;
}
}

View file

@ -0,0 +1,21 @@
package com.google.android.gms.cloudmessaging;
import androidx.annotation.IntDef;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
final class GmsOpCode {
@Retention(RetentionPolicy.SOURCE)
@IntDef(value = { SEND, BROADCAST_ACK, RPC_ACK, PROXY_RETAIN, PROXY_FETCH })
@interface Code {}
static final int SEND = 1;
static final int BROADCAST_ACK = 2;
static final int RPC_ACK = 3;
static final int PROXY_RETAIN = 4;
static final int PROXY_FETCH = 5;
private GmsOpCode() {}
}

View file

@ -0,0 +1,373 @@
package com.google.android.gms.cloudmessaging;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.util.Log;
import android.util.SparseArray;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.stats.ConnectionTracker;
import com.google.android.gms.common.util.concurrent.NamedThreadFactory;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.TaskCompletionSource;
import java.util.ArrayDeque;
import java.util.Queue;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
public final class MessengerIpcClient {
private static final String TAG = "MessengerIpcClient";
private static final String ACTION_REGISTER = "com.google.android.c2dm.intent.REGISTER";
private static final long TIMEOUT_SECONDS = 30L;
@Nullable
private static volatile MessengerIpcClient instance;
private final Context context;
private final ScheduledExecutorService executor;
private final AtomicInteger nextRequestId;
private Connection connection;
private MessengerIpcClient(Context context, ScheduledExecutorService executor) {
this.context = context.getApplicationContext();
this.executor = executor;
this.nextRequestId = new AtomicInteger(1);
this.connection = new Connection();
}
public static MessengerIpcClient getInstance(Context context) {
if (instance == null) {
synchronized (MessengerIpcClient.class) {
if (instance == null) {
instance = new MessengerIpcClient(
context,
Executors.unconfigurableScheduledExecutorService(
Executors.newScheduledThreadPool(1, new NamedThreadFactory(TAG))
)
);
}
}
}
return instance;
}
public Task<Bundle> sendRequest(@GmsOpCode.Code int what, Bundle data) {
return enqueue(new TwoWayRequest(nextRequestId(), what, data));
}
public Task<Void> sendOneWay(@GmsOpCode.Code int what, Bundle data) {
return enqueue(new OneWayRequest(nextRequestId(), what, data));
}
private <T> Task<T> enqueue(Request<T> request) {
synchronized (this) {
if (!connection.enqueueRequest(request)) {
connection = new Connection();
connection.enqueueRequest(request);
}
}
return request.completion.getTask();
}
private int nextRequestId() {
return nextRequestId.getAndIncrement();
}
private class Connection implements ServiceConnection {
private enum State { IDLE, BINDING, BOUND, UNBINDING, DEAD }
private State state = State.IDLE;
private final Messenger replyMessenger;
private Messenger serviceMessenger;
private final ConnectionTracker connectionTracker = ConnectionTracker.getInstance();
private final Queue<Request<?>> pendingRequests = new ArrayDeque<>();
private final SparseArray<Request<?>> activeRequests = new SparseArray<>();
private Connection() {
replyMessenger = new Messenger(
new Handler(Looper.getMainLooper(), this::handleReply)
);
}
synchronized boolean enqueueRequest(Request<?> request) {
switch (state) {
case IDLE:
state = State.BINDING;
pendingRequests.add(request);
bindService();
break;
case BINDING:
pendingRequests.add(request);
break;
case BOUND:
pendingRequests.add(request);
sendPendingRequests();
break;
default:
return false;
}
return true;
}
private void bindService() {
Log.v(TAG, "Starting bind to GmsCore");
final Intent intent = new Intent(ACTION_REGISTER);
intent.setPackage(GoogleApiAvailability.GOOGLE_PLAY_SERVICES_PACKAGE);
try {
boolean bound = connectionTracker.bindService(context, intent, this, Context.BIND_AUTO_CREATE);
if (bound) {
executor.schedule(this::onBindTimeout, TIMEOUT_SECONDS, TimeUnit.SECONDS);
} else {
handleDisconnection("Unable to bind to service");
}
} catch (SecurityException e) {
handleDisconnection("Unable to bind to service", e);
}
}
@MainThread
@Override
public void onServiceConnected(ComponentName name, IBinder binder) {
Log.v(TAG, "Service connected");
executor.execute(() -> handleBound(binder));
}
@MainThread
@Override
public void onServiceDisconnected(ComponentName name) {
Log.v(TAG, "Service disconnected");
executor.execute(() -> handleDisconnection("Service disconnected"));
}
private synchronized void onBindTimeout() {
if (state == State.BINDING) {
handleDisconnection("Timed out while binding");
}
}
private synchronized void handleBound(IBinder binder) {
try {
if (!"android.os.IMessenger".equals(binder.getInterfaceDescriptor())) {
throw new RemoteException("Invalid interface descriptor");
}
serviceMessenger = new Messenger(binder);
state = State.BOUND;
sendPendingRequests();
} catch (RemoteException e) {
handleDisconnection("Service connection failed", e);
}
}
private synchronized void handleDisconnection(@Nullable String reason) {
handleDisconnection(reason, null);
}
private synchronized void handleDisconnection(@Nullable String reason, @Nullable Throwable cause) {
switch (state) {
case IDLE:
throw new IllegalStateException();
case BINDING:
case BOUND:
state = State.DEAD;
connectionTracker.unbindService(context, this);
failAndClearAll(reason, cause);
break;
case UNBINDING:
state = State.DEAD;
break;
}
}
private void failAndClearAll(@Nullable String reason, @Nullable Throwable cause) {
final CloudMessagingException e = new CloudMessagingException(reason, cause);
for (Request<?> pendingRequest : pendingRequests) {
pendingRequest.fail(e);
}
pendingRequests.clear();
for (int i = 0; i < activeRequests.size(); i++) {
activeRequests.valueAt(i).fail(e);
}
activeRequests.clear();
}
private void sendPendingRequests() {
executor.execute(() -> {
while (true) {
Request<?> request;
synchronized (this) {
if (state != State.BOUND) {
return;
}
request = pendingRequests.poll();
if (request == null) {
maybeUnbind();
return;
}
activeRequests.put(request.id, request);
executor.schedule(() -> timeoutRequest(request.id), TIMEOUT_SECONDS, TimeUnit.SECONDS);
}
Message msg = Message.obtain();
msg.what = request.what;
msg.arg1 = request.id;
msg.replyTo = replyMessenger;
Bundle data = new Bundle();
data.putBoolean("oneWay", request.isOneWay());
data.putString("pkg", context.getPackageName());
data.putBundle("data", request.payload);
msg.setData(data);
try {
serviceMessenger.send(msg);
} catch (RemoteException e) {
handleDisconnection(e.getMessage());
}
}
});
}
private synchronized void timeoutRequest(int requestId) {
Request<?> r = activeRequests.get(requestId);
if (r != null) {
Log.w(TAG, "Timing out request: " + requestId);
activeRequests.remove(requestId);
r.fail(new CloudMessagingException("Timed out waiting for response"));
maybeUnbind();
}
}
private boolean handleReply(Message msg) {
final Request<?> request;
synchronized (this) {
int requestId = msg.arg1;
request = activeRequests.get(requestId);
if (request == null) {
Log.w(TAG, "Unknown request response: " + requestId);
return true;
}
activeRequests.remove(requestId);
maybeUnbind();
}
Bundle data = msg.getData();
if (data.getBoolean("unsupported", false)) {
request.fail(new CloudMessagingException("Not supported by GmsCore"));
} else {
request.onResponse(data);
}
return true;
}
private synchronized void maybeUnbind() {
if (state == State.BOUND && activeRequests.size() == 0 && pendingRequests.isEmpty()) {
Log.v(TAG, "Finished handling requests, unbinding");
state = State.UNBINDING;
connectionTracker.unbindService(context, this);
}
}
}
abstract static class Request<T> {
final int id;
final int what;
final Bundle payload;
final TaskCompletionSource<T> completion = new TaskCompletionSource<>();
Request(int id, int what, Bundle payload) {
this.id = id;
this.what = what;
this.payload = payload;
}
final void fail(CloudMessagingException e) {
completion.setException(e);
}
final void complete(T result) {
completion.setResult(result);
}
abstract boolean isOneWay();
abstract void onResponse(Bundle response);
@Override
@NonNull
public String toString() {
return "Request { what=" + what + " id=" + id + " oneWay=" + isOneWay() + "}";
}
}
static final class OneWayRequest extends Request<Void> {
OneWayRequest(int id, int what, Bundle payload) {
super(id, what, payload);
}
@Override
boolean isOneWay() {
return true;
}
@Override
void onResponse(Bundle response) {
if (response.getBoolean("ack", false)) {
complete(null);
} else {
fail(new CloudMessagingException("Invalid response to one way request"));
}
}
}
static final class TwoWayRequest extends Request<Bundle> {
TwoWayRequest(int id, int what, Bundle payload) {
super(id, what, payload);
}
@Override
boolean isOneWay() {
return false;
}
@Override
void onResponse(Bundle response) {
Bundle data = response.getBundle("data");
if (data == null) {
data = Bundle.EMPTY;
}
complete(data);
}
}
}

View file

@ -0,0 +1,37 @@
package com.google.android.gms.cloudmessaging;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.util.Log;
import com.google.android.gms.common.wrappers.PackageManagerWrapper;
import com.google.android.gms.common.wrappers.Wrappers;
import static com.google.android.gms.common.GoogleApiAvailabilityLight.GOOGLE_PLAY_SERVICES_PACKAGE;
final class Metadata {
private static final String TAG = "Metadata";
private final PackageManagerWrapper packageManager;
private Integer gmsPackageVersion;
public Metadata(Context context) {
this.packageManager = Wrappers.packageManager(context);
}
public int getGmsPackageVersion() {
if (gmsPackageVersion == null) {
try {
PackageInfo packageInfo = packageManager.getPackageInfo(GOOGLE_PLAY_SERVICES_PACKAGE, 0);
gmsPackageVersion = packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
Log.w(TAG, "Failed to find package: " + e);
return -1;
}
}
return gmsPackageVersion;
}
}

View file

@ -0,0 +1,96 @@
package com.google.android.gms.cloudmessaging;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.Log;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import com.google.android.gms.tasks.Task;
import com.google.android.gms.tasks.Tasks;
import java.io.IOException;
@Keep
public class Rpc {
private static final String TAG = "Rpc";
private static final String SERVICE_NOT_AVAILABLE = "SERVICE_NOT_AVAILABLE";
private static final int MIN_VERSION_FOR_MESSAGE_ACK = 233700000;
private static final int MIN_VERSION_FOR_PROXY_RETENTION = 241100000;
private final MessengerIpcClient ipcClient;
private final Metadata metadata;
public Rpc(@NonNull Context context) {
this.ipcClient = MessengerIpcClient.getInstance(context);
this.metadata = new Metadata(context);
}
@NonNull
public Task<Bundle> send(@NonNull Bundle data) {
return ipcClient
.sendRequest(GmsOpCode.SEND, data)
.continueWith(Runnable::run, task -> {
if (task.isSuccessful()) {
return task.getResult();
} else {
Exception e = task.getException();
Log.d(TAG, "Error making request: " + e);
throw new IOException(SERVICE_NOT_AVAILABLE, e);
}
});
}
@NonNull
public Task<Void> messageHandled(@NonNull CloudMessage message) {
if (metadata.getGmsPackageVersion() < MIN_VERSION_FOR_MESSAGE_ACK) {
return serviceNotAvailable();
}
Bundle response = CloudMessageBundle.forMessage(message);
return ipcClient.sendOneWay(GmsOpCode.RPC_ACK, response);
}
@NonNull
public Task<Void> setRetainProxiedNotifications(boolean retain) {
if (!BuildConfig.NOTIFICATION_PAYLOAD_ENABLED) {
return serviceNotAvailable();
}
if (metadata.getGmsPackageVersion() < MIN_VERSION_FOR_PROXY_RETENTION) {
return serviceNotAvailable();
}
Bundle bundle = new Bundle();
bundle.putBoolean("proxy_retention", retain);
return ipcClient.sendOneWay(GmsOpCode.PROXY_RETAIN, bundle);
}
@NonNull
public Task<CloudMessage> getProxiedNotificationData() {
if (!BuildConfig.NOTIFICATION_PAYLOAD_ENABLED) {
return serviceNotAvailable();
}
if (metadata.getGmsPackageVersion() < MIN_VERSION_FOR_PROXY_RETENTION) {
return serviceNotAvailable();
}
return ipcClient
.sendRequest(GmsOpCode.PROXY_FETCH, Bundle.EMPTY)
.continueWith(Runnable::run, task -> {
Bundle bundle = task.getResult();
Parcelable intent = bundle.getParcelable("notification_data");
if (!(intent instanceof Intent)) {
return null;
}
return new CloudMessage((Intent) intent);
});
}
@NonNull
private static <T> Task<T> serviceNotAvailable() {
return Tasks.forException(new IOException(SERVICE_NOT_AVAILABLE));
}
}

View file

@ -0,0 +1,18 @@
package com.google.firebase;
import androidx.annotation.Keep;
@Keep
public class FirebaseException extends Exception {
@Deprecated
protected FirebaseException() {}
public FirebaseException(String message) {
super(message);
}
public FirebaseException(String message, Throwable cause) {
super(message, cause);
}
}

View file

@ -0,0 +1,29 @@
package com.google.firebase.iid.internal;
import androidx.annotation.Keep;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import com.google.android.gms.tasks.Task;
import java.io.IOException;
@Keep
public interface FirebaseInstanceIdInternal {
void deleteToken(@NonNull String senderId, @NonNull String scope) throws IOException;
String getId();
@Nullable
String getToken();
@NonNull
Task<String> getTokenTask();
void addNewTokenListener(NewTokenListener listener);
interface NewTokenListener {
void onNewToken(String token);
}
}