0
0
Fork 0
mirror of https://github.com/YTVanced/VancedMicroG synced 2024-11-15 23:45:06 +00:00

Merge pull request #3 from Mattis6666/master

Sync
This commit is contained in:
Tornike Khintibidze 2020-07-20 16:15:37 +04:00 committed by GitHub
commit 4bdc106afe
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
39 changed files with 1 additions and 4179 deletions

View file

@ -75,7 +75,7 @@ public class ForegroundServiceContext extends ContextWrapper {
return new Notification.Builder(context, channel.getId()) return new Notification.Builder(context, channel.getId())
.setOngoing(true) .setOngoing(true)
.setContentTitle("Running in background") .setContentTitle("Running in background")
.setContentText("This notification ensures, that microG does not get killed.") .setContentText("This notification ensures that microG does not get killed.")
.setSmallIcon(R.drawable.ic_foreground_notification) .setSmallIcon(R.drawable.ic_foreground_notification)
.build(); .build();
} }

View file

@ -1,47 +0,0 @@
/*
* Copyright 2013-2015 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.
*/
apply plugin: 'com.android.library'
String getMyVersionName() {
def stdout = new ByteArrayOutputStream()
if (rootProject.file("gradlew").exists())
exec { commandLine 'git', 'describe', '--tags', '--always', '--dirty'; standardOutput = stdout }
else // automatic build system, don't tag dirty
exec { commandLine 'git', 'describe', '--tags', '--always'; standardOutput = stdout }
return stdout.toString().trim().substring(1)
}
android {
compileSdkVersion androidCompileSdk()
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName getMyVersionName()
minSdkVersion androidMinSdk()
targetSdkVersion androidTargetSdk()
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
api project(':play-services-base')
api project(':play-services-cast-api')
}

View file

@ -1,34 +0,0 @@
#
# 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.
#
POM_NAME=Play Services Cast Library
POM_DESCRIPTION=The Play Services Library module to access the Cast API
POM_PACKAGING=aar
POM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=mar-v-in
POM_DEVELOPER_NAME=Marvin W

View file

@ -1,18 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2013-2017 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.
-->
<manifest package="org.microg.gms.cast"/>

View file

@ -1,223 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.cast;
import android.os.Bundle;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Result;
import com.google.android.gms.common.api.Status;
import org.microg.gms.cast.CastApiBuilder;
import org.microg.gms.cast.CastApiImpl;
import org.microg.gms.common.PublicApi;
import java.io.IOException;
@PublicApi
public final class Cast {
/**
* A constant indicating that the Google Cast device is not the currently active video input.
*/
public static final int ACTIVE_INPUT_STATE_NO = 0;
/**
* A constant indicating that it is not known (and/or not possible to know) whether the Google Cast device is
* the currently active video input. Active input state can only be reported when the Google Cast device is
* connected to a TV or AVR with CEC support.
*/
public static final int ACTIVE_INPUT_STATE_UNKNOWN = -1;
/**
* A constant indicating that the Google Cast device is the currently active video input.
*/
public static final int ACTIVE_INPUT_STATE_YES = 1;
/**
* A boolean extra for the connection hint bundle passed to
* {@link GoogleApiClient.ConnectionCallbacks#onConnected(Bundle)} that indicates that the connection was
* re-established, but the receiver application that was in use at the time of the connection loss is no longer
* running on the receiver.
*/
public static final String EXTRA_APP_NO_LONGER_RUNNING = "com.google.android.gms.cast.EXTRA_APP_NO_LONGER_RUNNING";
/**
* The maximum raw message length (in bytes) that is supported by a Cast channel.
*/
public static final int MAX_MESSAGE_LENGTH = 65536;
/**
* The maximum length (in characters) of a namespace name.
*/
public static final int MAX_NAMESPACE_LENGTH = 128;
/**
* A constant indicating that the Google Cast device is not currently in standby.
*/
public static final int STANDBY_STATE_NO = 0;
/**
* A constant indicating that it is not known (and/or not possible to know) whether the Google Cast device is
* currently in standby. Standby state can only be reported when the Google Cast device is connected to a TV or
* AVR with CEC support.
*/
public static final int STANDBY_STATE_UNKNOWN = -1;
/**
* A constant indicating that the Google Cast device is currently in standby.
*/
public static final int STANDBY_STATE_YES = 1;
/**
* Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the Cast features.
*/
public static final Api<CastOptions> API = new Api<CastOptions>(new CastApiBuilder());
/**
* An implementation of the CastApi interface. The interface is used to interact with a cast device.
*/
public static final Cast.CastApi CastApi = new CastApiImpl();
private Cast() {
}
public interface ApplicationConnectionResult extends Result {
ApplicationMetadata getApplicationMetadata();
String getApplicationStatus();
String getSessionId();
boolean getWasLaunched();
}
public interface CastApi {
int getActiveInputState(GoogleApiClient client);
ApplicationMetadata getApplicationMetadata(GoogleApiClient client);
String getApplicationStatus(GoogleApiClient client);
int getStandbyState(GoogleApiClient client);
double getVolume(GoogleApiClient client);
boolean isMute(GoogleApiClient client);
PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client);
PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId, String sessionId);
PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId);
PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, LaunchOptions launchOptions);
PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId);
@Deprecated
PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, boolean relaunchIfRunning);
PendingResult<Status> leaveApplication(GoogleApiClient client);
void removeMessageReceivedCallbacks(GoogleApiClient client, String namespace) throws IOException;
void requestStatus(GoogleApiClient client) throws IOException;
PendingResult<Status> sendMessage(GoogleApiClient client, String namespace, String message);
void setMessageReceivedCallbacks(GoogleApiClient client, String namespace, Cast.MessageReceivedCallback callbacks) throws IOException;
void setMute(GoogleApiClient client, boolean mute) throws IOException;
void setVolume(GoogleApiClient client, double volume) throws IOException;
PendingResult<Status> stopApplication(GoogleApiClient client);
PendingResult<Status> stopApplication(GoogleApiClient client, String sessionId);
}
public static class CastOptions implements Api.ApiOptions.HasOptions {
private final CastDevice castDevice;
private final Listener castListener;
private final boolean verboseLoggingEnabled;
public CastOptions(CastDevice castDevice, Listener castListener, boolean verboseLoggingEnabled) {
this.castDevice = castDevice;
this.castListener = castListener;
this.verboseLoggingEnabled = verboseLoggingEnabled;
}
@Deprecated
public static Builder builder(CastDevice castDevice, Listener castListener) {
return new Builder(castDevice, castListener);
}
public static class Builder {
private final CastDevice castDevice;
private final Listener castListener;
private boolean verboseLoggingEnabled;
public Builder(CastDevice castDevice, Listener castListener) {
this.castDevice = castDevice;
this.castListener = castListener;
}
public CastOptions build() {
return new CastOptions(castDevice, castListener, verboseLoggingEnabled);
}
public Builder setVerboseLoggingEnabled(boolean verboseLoggingEnabled) {
this.verboseLoggingEnabled = verboseLoggingEnabled;
return this;
}
}
}
public static class Listener {
public void onActiveInputStateChanged(int activeInputState) {
}
public void onApplicationDisconnected(int statusCode) {
}
public void onApplicationMetadataChanged(ApplicationMetadata applicationMetadata) {
}
public void onApplicationStatusChanged() {
}
public void onStandbyStateChanged(int standbyState) {
}
public void onVolumeChanged() {
}
}
public interface MessageReceivedCallback {
void onMessageReceived(CastDevice castDevice, String namespace, String message);
}
}

View file

@ -1,33 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.cast;
import android.annotation.TargetApi;
import android.app.Presentation;
import android.content.Context;
import android.view.Display;
@TargetApi(17)
public class CastPresentation extends Presentation {
public CastPresentation(Context outerContext, Display display) {
super(outerContext, display);
}
public CastPresentation(Context outerContext, Display display, int theme) {
super(outerContext, display, theme);
}
}

View file

@ -1,76 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.cast;
import android.view.Display;
import com.google.android.gms.common.api.Api;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.Result;
import com.google.android.gms.common.api.Status;
import org.microg.gms.cast.CastRemoteDisplayApiBuilder;
import org.microg.gms.cast.CastRemoteDisplayApiImpl;
import org.microg.gms.common.PublicApi;
@PublicApi
public final class CastRemoteDisplay {
/**
* Token to pass to {@link GoogleApiClient.Builder#addApi(Api)} to enable the CastRemoteDisplay features.
*/
public static final Api<CastRemoteDisplayOptions> API = new Api<CastRemoteDisplayOptions>(new CastRemoteDisplayApiBuilder());
/**
* An implementation of the CastRemoteDisplayAPI interface. The interface is used to interact with a cast device.
*/
public static final CastRemoteDisplayApi CastApi = new CastRemoteDisplayApiImpl();
private CastRemoteDisplay() {
}
public static final class CastRemoteDisplayOptions implements Api.ApiOptions.HasOptions {
private CastDevice castDevice;
private CastRemoteDisplaySessionCallbacks callbacks;
private CastRemoteDisplayOptions(CastDevice castDevice, CastRemoteDisplaySessionCallbacks callbacks) {
this.castDevice = castDevice;
this.callbacks = callbacks;
}
public static final class Builder {
private CastDevice castDevice;
private CastRemoteDisplaySessionCallbacks callbacks;
public Builder(CastDevice castDevice, CastRemoteDisplaySessionCallbacks callbacks) {
this.castDevice = castDevice;
this.callbacks = callbacks;
}
public CastRemoteDisplayOptions build() {
return new CastRemoteDisplayOptions(castDevice, callbacks);
}
}
}
public interface CastRemoteDisplaySessionCallbacks {
void onRemoteDisplayEnded(Status status);
}
public interface CastRemoteDisplaySessionResult extends Result {
Display getPresentationDisplay();
}
}

View file

@ -1,26 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.cast;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
public interface CastRemoteDisplayApi {
PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> startRemoteDisplay(GoogleApiClient apiClient, String applicationId);
PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> stopRemoteDisplay(GoogleApiClient apiClient);
}

View file

@ -1,28 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.cast;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
public class CastRemoteDisplayLocalService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
}

View file

@ -1,34 +0,0 @@
/*
* Copyright (C) 2013-2017 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.cast;
import android.content.Context;
import android.os.Looper;
import com.google.android.gms.cast.Cast;
import com.google.android.gms.common.api.AccountInfo;
import com.google.android.gms.common.api.GoogleApiClient;
import org.microg.gms.common.api.ApiBuilder;
import org.microg.gms.common.api.ApiConnection;
public class CastApiBuilder implements ApiBuilder<Cast.CastOptions>{
@Override
public ApiConnection build(Context context, Looper looper, Cast.CastOptions options, AccountInfo accountInfo, GoogleApiClient.ConnectionCallbacks callbacks, GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
return new CastClientImpl(context, options, callbacks, connectionFailedListener);
}
}

View file

@ -1,134 +0,0 @@
/*
* Copyright (C) 2013-2017 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.cast;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.gms.cast.Cast;
import com.google.android.gms.cast.LaunchOptions;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
import com.google.android.gms.common.api.Status;
import java.io.IOException;
// TODO
public class CastApiImpl implements Cast.CastApi {
@Override
public int getActiveInputState(GoogleApiClient client) {
return 0;
}
@Override
public ApplicationMetadata getApplicationMetadata(GoogleApiClient client) {
return null;
}
@Override
public String getApplicationStatus(GoogleApiClient client) {
return null;
}
@Override
public int getStandbyState(GoogleApiClient client) {
return 0;
}
@Override
public double getVolume(GoogleApiClient client) {
return 0;
}
@Override
public boolean isMute(GoogleApiClient client) {
return false;
}
@Override
public PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client) {
return null;
}
@Override
public PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId, String sessionId) {
return null;
}
@Override
public PendingResult<Cast.ApplicationConnectionResult> joinApplication(GoogleApiClient client, String applicationId) {
return null;
}
@Override
public PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, LaunchOptions launchOptions) {
return null;
}
@Override
public PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId) {
return null;
}
@Override
public PendingResult<Cast.ApplicationConnectionResult> launchApplication(GoogleApiClient client, String applicationId, boolean relaunchIfRunning) {
return null;
}
@Override
public PendingResult<Status> leaveApplication(GoogleApiClient client) {
return null;
}
@Override
public void removeMessageReceivedCallbacks(GoogleApiClient client, String namespace) throws IOException {
}
@Override
public void requestStatus(GoogleApiClient client) throws IOException {
}
@Override
public PendingResult<Status> sendMessage(GoogleApiClient client, String namespace, String message) {
return null;
}
@Override
public void setMessageReceivedCallbacks(GoogleApiClient client, String namespace, Cast.MessageReceivedCallback callbacks) throws IOException {
}
@Override
public void setMute(GoogleApiClient client, boolean mute) throws IOException {
}
@Override
public void setVolume(GoogleApiClient client, double volume) throws IOException {
}
@Override
public PendingResult<Status> stopApplication(GoogleApiClient client) {
return null;
}
@Override
public PendingResult<Status> stopApplication(GoogleApiClient client, String sessionId) {
return null;
}
}

View file

@ -1,29 +0,0 @@
/*
* Copyright (C) 2013-2017 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.cast;
import android.content.Context;
import com.google.android.gms.cast.Cast;
import com.google.android.gms.common.api.GoogleApiClient;
import org.microg.gms.common.DummyApiConnection;
public class CastClientImpl extends DummyApiConnection {
public CastClientImpl(Context context, Cast.CastOptions options, GoogleApiClient.ConnectionCallbacks callbacks, GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
}
}

View file

@ -1,35 +0,0 @@
/*
* Copyright (C) 2013-2017 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.cast;
import android.content.Context;
import android.os.Looper;
import com.google.android.gms.cast.CastRemoteDisplay;
import com.google.android.gms.common.api.AccountInfo;
import com.google.android.gms.common.api.GoogleApiClient;
import org.microg.gms.common.DummyApiConnection;
import org.microg.gms.common.api.ApiBuilder;
import org.microg.gms.common.api.ApiConnection;
public class CastRemoteDisplayApiBuilder implements ApiBuilder<CastRemoteDisplay.CastRemoteDisplayOptions> {
@Override
public ApiConnection build(Context context, Looper looper, CastRemoteDisplay.CastRemoteDisplayOptions options, AccountInfo accountInfo, GoogleApiClient.ConnectionCallbacks callbacks, GoogleApiClient.OnConnectionFailedListener connectionFailedListener) {
return new DummyApiConnection();
}
}

View file

@ -1,34 +0,0 @@
/*
* Copyright (C) 2013-2017 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.cast;
import com.google.android.gms.cast.CastRemoteDisplay;
import com.google.android.gms.cast.CastRemoteDisplayApi;
import com.google.android.gms.common.api.GoogleApiClient;
import com.google.android.gms.common.api.PendingResult;
public class CastRemoteDisplayApiImpl implements CastRemoteDisplayApi {
@Override
public PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> startRemoteDisplay(GoogleApiClient apiClient, String applicationId) {
return null;
}
@Override
public PendingResult<CastRemoteDisplay.CastRemoteDisplaySessionResult> stopRemoteDisplay(GoogleApiClient apiClient) {
return null;
}
}

View file

@ -1,47 +0,0 @@
/*
* Copyright 2013-2015 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.
*/
apply plugin: 'com.android.library'
String getMyVersionName() {
def stdout = new ByteArrayOutputStream()
if (rootProject.file("gradlew").exists())
exec { commandLine 'git', 'describe', '--tags', '--always', '--dirty'; standardOutput = stdout }
else // automatic build system, don't tag dirty
exec { commandLine 'git', 'describe', '--tags', '--always'; standardOutput = stdout }
return stdout.toString().trim().substring(1)
}
android {
compileSdkVersion androidCompileSdk()
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName getMyVersionName()
minSdkVersion androidMinSdk()
targetSdkVersion androidTargetSdk()
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
api project(':play-services-iid')
// compile project(':play-services-measurement')
}

View file

@ -1,34 +0,0 @@
#
# 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.
#
POM_NAME=Play Services GCM Library
POM_DESCRIPTION=The Play Services Library module to access Google Cloud Messaging
POM_PACKAGING=aar
POM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=mar-v-in
POM_DEVELOPER_NAME=Marvin W

View file

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2013-2017 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.
-->
<manifest package="org.microg.gms.gcm"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Permissions required for GCM -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<!-- Move to play-services-measurement -->
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
</manifest>

View file

@ -1,194 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Intent;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.IBinder;
import android.util.Log;
import org.microg.gms.common.PublicApi;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;
import static org.microg.gms.gcm.GcmConstants.ACTION_NOTIFICATION_OPEN;
import static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;
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_MESSAGE_TYPE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_PENDING_INTENT;
import static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_DELETED_MESSAGE;
import static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_GCM;
import static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_SEND_ERROR;
import static org.microg.gms.gcm.GcmConstants.MESSAGE_TYPE_SEND_EVENT;
/**
* Base class for communicating with Google Cloud Messaging.
* <p/>
* It also provides functionality such as automatically displaying
* <a href="https://developer.android.com/google/gcm/server.html">notifications when requested by app server</a>.
* <p/>
* Override base class methods to handle any events required by the application.
* Methods are invoked asynchronously.
* <p/>
* Include the following in the manifest:
* <pre>
* <service
* android:name=".YourGcmListenerService"
* android:exported="false" >
* <intent-filter>
* <action android:name="com.google.android.c2dm.intent.RECEIVE" />
* </intent-filter>
* </service></pre>
*/
@PublicApi
public abstract class GcmListenerService extends Service {
private static final String TAG = "GcmListenerService";
private final Object lock = new Object();
private int startId;
private int counter = 0;
public final IBinder onBind(Intent intent) {
return null;
}
/**
* Called when GCM server deletes pending messages due to exceeded
* storage limits, for example, when the device cannot be reached
* for an extended period of time.
* <p/>
* It is recommended to retrieve any missing messages directly from the
* app server.
*/
public void onDeletedMessages() {
// To be overwritten
}
/**
* Called when a message is received.
*
* @param from describes message sender.
* @param data message data as String key/value pairs.
*/
public void onMessageReceived(String from, Bundle data) {
// To be overwritten
}
/**
* Called when an upstream message has been successfully sent to the
* GCM connection server.
*
* @param msgId of the upstream message sent using
* {@link com.google.android.gms.gcm.GoogleCloudMessaging#send(java.lang.String, java.lang.String, android.os.Bundle)}.
*/
public void onMessageSent(String msgId) {
// To be overwritten
}
/**
* Called when there was an error sending an upstream message.
*
* @param msgId of the upstream message sent using
* {@link com.google.android.gms.gcm.GoogleCloudMessaging#send(java.lang.String, java.lang.String, android.os.Bundle)}.
* @param error description of the error.
*/
public void onSendError(String msgId, String error) {
// To be overwritten
}
public final int onStartCommand(final Intent intent, int flags, int startId) {
synchronized (lock) {
this.startId = startId;
this.counter++;
}
if (intent != null) {
if (ACTION_NOTIFICATION_OPEN.equals(intent.getAction())) {
handlePendingNotification(intent);
finishCounter();
GcmReceiver.completeWakefulIntent(intent);
} else if (ACTION_C2DM_RECEIVE.equals(intent.getAction())) {
new AsyncTask<Void, Void, Void>() {
@Override
protected Void doInBackground(Void... params) {
handleC2dmMessage(intent);
return null;
}
}.execute();
} else {
Log.w(TAG, "Unknown intent action: " + intent.getAction());
}
return START_REDELIVER_INTENT;
} else {
finishCounter();
return START_NOT_STICKY;
}
}
private void handleC2dmMessage(Intent intent) {
try {
String messageType = intent.getStringExtra(EXTRA_MESSAGE_TYPE);
if (messageType == null || MESSAGE_TYPE_GCM.equals(messageType)) {
String from = intent.getStringExtra(EXTRA_FROM);
Bundle data = intent.getExtras();
data.remove(EXTRA_MESSAGE_TYPE);
data.remove("android.support.content.wakelockid"); // WakefulBroadcastReceiver.EXTRA_WAKE_LOCK_ID
data.remove(EXTRA_FROM);
onMessageReceived(from, data);
} else if (MESSAGE_TYPE_DELETED_MESSAGE.equals(messageType)) {
onDeletedMessages();
} else if (MESSAGE_TYPE_SEND_EVENT.equals(messageType)) {
onMessageSent(intent.getStringExtra(EXTRA_MESSAGE_ID));
} else if (MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
onSendError(intent.getStringExtra(EXTRA_MESSAGE_ID), intent.getStringExtra(EXTRA_ERROR));
} else {
Log.w(TAG, "Unknown message type: " + messageType);
}
finishCounter();
} finally {
GcmReceiver.completeWakefulIntent(intent);
}
}
private void handlePendingNotification(Intent intent) {
PendingIntent pendingIntent = intent.getParcelableExtra(EXTRA_PENDING_INTENT);
if (pendingIntent != null) {
try {
pendingIntent.send();
} catch (PendingIntent.CanceledException e) {
Log.w(TAG, "Notification cancelled", e);
}
} else {
Log.w(TAG, "Notification was null");
}
}
private void finishCounter() {
synchronized (lock) {
this.counter--;
if (counter == 0) {
stopSelfResult(startId);
}
}
}
}

View file

@ -1,244 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.app.PendingIntent;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.os.Bundle;
import android.text.TextUtils;
import java.util.List;
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
import static org.microg.gms.gcm.GcmConstants.ACTION_SCHEDULE;
import static org.microg.gms.gcm.GcmConstants.ACTION_TASK_READY;
import static org.microg.gms.gcm.GcmConstants.EXTRA_COMPONENT;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SCHEDULER_ACTION;
import static org.microg.gms.gcm.GcmConstants.EXTRA_TAG;
import static org.microg.gms.gcm.GcmConstants.SCHEDULER_ACTION_CANCEL;
import static org.microg.gms.gcm.GcmConstants.SCHEDULER_ACTION_CANCEL_ALL;
import static org.microg.gms.gcm.GcmConstants.SCHEDULER_ACTION_SCHEDULE;
/**
* Class to create apps with robust "send-to-sync", which is the mechanism to sync data with
* servers where new information is available.
* <p/>
* You can use the API to schedule network-oriented tasks, and let Google Play services batch
* network operations across the system. This greatly simplifies the implementation of common
* patterns, such as waiting for network connectivity, network retries, and backoff.
* <p/>
* Tasks must be scheduled based on an execution window in time. During this execution window
* the scheduler will use its discretion in picking an optimal execution time, based on network
* availability (whether the device has connectivity), network activity (whether packages are
* actively being transferred). and load (how many other pending tasks are available for
* execution at that point in time). <strong>If none of these factors are influential, the
* scheduler will always wait until the end of the specified window.</strong>
* <p/>
* To receive the notification from the scheduler that a task is ready to be executed, your
* client app must implement a {@link com.google.android.gms.gcm.GcmTaskService} and filter
* on the action {@link com.google.android.gms.gcm.GcmTaskService#SERVICE_ACTION_EXECUTE_TASK}.
* <p/>
* Note that tags of arbitrary length are <strong>not</strong> allowed; if the tag you
* provide is greater than 100 characters an exception will be thrown when you try to create your
* {@link com.google.android.gms.gcm.Task} object.
* <p/>
* The service should be protected by the permission
* com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE which is used by Google Play
* Services. This prevents other code from invoking the broadcast receiver. Here is an excerpt from
* a sample manifest:
* <pre>
* <service android:name=".MyUploadService"
* android:exported="true"
* android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE" >
* <intent-filter>
* <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY" />
* </intent-filter>
* </service>
* </pre>
* An execution contains the tag identifier which your client app provides. This identifies
* one "task", or piece of work, that you mean to perform. Consider the tag to be the key to which
* your task logic is paired.
* <pre>
* // Schedule a task to occur between five and fifteen seconds from now:
* OneoffTask myTask = new OneoffTask.Builder()
* .setService(MyGcmTaskService.class)
* .setExecutionWindow(
* 5 * DateUtil.MINUTE_IN_SECONDS, 15 * DateUtil.MINUTE_IN_SECONDS)
* .setTag("test-upload")
* .build();
* GcmNetworkManager.get(this).schedule(myTask);
* ...
* // Implement service logic to be notified when the task elapses:
* MyUploadService extends GcmTaskService {
*
* @Override public int onRunTask(TaskParams params) {
* // Do some upload work.
* return GcmNetworkManager.RESULT_SUCCESS;
* }
* }
* </pre>
* To help in debugging your tasks, run
* <code>adb shell dumpsys activity service GcmService --endpoints [...]</code>
* If you want to execute your task immediately (for debugging) you can execute tasks from the
* command line via:
* <code>adb shell am broadcast -a "com.google.android.gms.gcm.ACTION_TRIGGER_TASK" \
* -e component <COMPONENT_NAME> -e tag <TAG></code>
* Where <strong>COMPONENT_NAME</strong>: The full
* {@link ComponentName#flattenToString()} returned for your implementation of
* {@link com.google.android.gms.gcm.GcmTaskService}.
* <strong>TAG</strong>: the tag you want to have land in
* {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}
* Example usage for the gradle target GcmTestProxy service:
* <code>adb shell am broadcast -a "com.google.android.gms.gcm.ACTION_TRIGGER_TASK" \
* -e component "com.google.android.gms.gcm.test.proxy/.internal.nstest.TestNetworkTaskService" \
* -e tag "upload"</code>
* <strong>This is only available if the device is a test-keys build. This will replace any
* previously scheduled task with the same tag!</strong> This will have especially awkward effects
* if your original task was a periodic, because the debug task is scheduled as a one-off.
*/
public class GcmNetworkManager {
/**
* Indicates a task has failed, but not to reschedule.
*/
public static final int RESULT_FAILURE = 2;
/**
* Indicates a task has failed to execute, and must be retried with back-off.
*/
public static final int RESULT_RESCHEDULE = 1;
/**
* Indicates a task has successfully been executed, and can be removed from the queue.
*/
public static final int RESULT_SUCCESS = 0;
private static GcmNetworkManager INSTANCE;
private final Context context;
private GcmNetworkManager(Context context) {
this.context = context;
}
/**
* Cancels all tasks previously scheduled against the provided GcmTaskService. Note that a
* cancel will have no effect on an in-flight task.
*
* @param gcmTaskService The endpoint for which you want to cancel all outstanding tasks.
*/
public void cancelAllTasks(Class<? extends GcmTaskService> gcmTaskService) {
validateService(gcmTaskService.getName());
Intent scheduleIntent = createScheduleIntent();
if (scheduleIntent != null) {
scheduleIntent.putExtra(EXTRA_SCHEDULER_ACTION, SCHEDULER_ACTION_CANCEL_ALL);
scheduleIntent.putExtra(EXTRA_COMPONENT, new ComponentName(context, gcmTaskService));
context.sendBroadcast(scheduleIntent);
}
}
/**
* Cancel a task, specified by tag. Note that a cancel will have no effect on an in-flight
* task.
*
* @param tag The tag to uniquely identify this task on this endpoint.
* @param gcmTaskService The endpoint for which you want to cancel all outstanding tasks.
*/
public void cancelTask(String tag, Class<? extends GcmTaskService> gcmTaskService) {
if (TextUtils.isEmpty(tag) || tag.length() < 100) throw new IllegalArgumentException("tag invalid");
validateService(gcmTaskService.getName());
Intent scheduleIntent = createScheduleIntent();
if (scheduleIntent != null) {
scheduleIntent.putExtra(EXTRA_SCHEDULER_ACTION, SCHEDULER_ACTION_CANCEL);
scheduleIntent.putExtra(EXTRA_TAG, tag);
scheduleIntent.putExtra(EXTRA_COMPONENT, new ComponentName(context, gcmTaskService));
context.sendBroadcast(scheduleIntent);
}
}
/**
* Use this function to access the GcmNetworkManager API.
*
* @param context Context of the calling app.
* @return GcmNetworkManager object.
*/
public static GcmNetworkManager getInstance(Context context) {
synchronized (GcmNetworkManager.class) {
if (INSTANCE == null) {
INSTANCE = new GcmNetworkManager(context);
}
return INSTANCE;
}
}
/**
* Entry point to schedule a task with the network manager.
* <p/>
* If GooglePlayServices is unavailable (upgrading, missing, etc). This call will fail silently.
* You should wrap it in a call to {@link com.google.android.gms.common.GooglePlayServicesUtil#isGooglePlayServicesAvailable(android.content.Context)}</p>
*
* @param task Task constructed using {@link com.google.android.gms.gcm.Task.Builder}. Can be
* an instance of {@link com.google.android.gms.gcm.PeriodicTask} or
* {@link com.google.android.gms.gcm.OneoffTask}.
*/
public void schedule(Task task) {
validateService(task.getServiceName());
Intent scheduleIntent = createScheduleIntent();
if (scheduleIntent != null) {
Bundle extras = scheduleIntent.getExtras();
extras.putString(EXTRA_SCHEDULER_ACTION, SCHEDULER_ACTION_SCHEDULE);
task.toBundle(extras);
scheduleIntent.putExtras(extras);
context.sendBroadcast(scheduleIntent);
}
}
private Intent createScheduleIntent() {
if (!packageExists(GMS_PACKAGE_NAME)) return null;
Intent scheduleIntent = new Intent(ACTION_SCHEDULE);
scheduleIntent.setPackage(GMS_PACKAGE_NAME);
scheduleIntent.putExtra("app", PendingIntent.getBroadcast(context, 0, new Intent(), 0));
return scheduleIntent;
}
private boolean packageExists(String packageName) {
try {
PackageManager pm = context.getPackageManager();
pm.getPackageInfo(packageName, 0);
return true;
} catch (PackageManager.NameNotFoundException e) {
return false;
}
}
private void validateService(String serviceName) {
if (serviceName == null) throw new NullPointerException("No service provided");
Intent taskIntent = new Intent(ACTION_TASK_READY);
taskIntent.setPackage(context.getPackageName());
PackageManager pm = context.getPackageManager();
List<ResolveInfo> serviceResolves = pm.queryIntentServices(taskIntent, 0);
if (serviceResolves == null || serviceResolves.isEmpty())
throw new IllegalArgumentException("No service found");
for (ResolveInfo info : serviceResolves) {
if (serviceName.equals(info.serviceInfo.name)) return;
}
throw new IllegalArgumentException("Service not supported.");
}
}

View file

@ -1,121 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.content.Context;
import android.os.Bundle;
import android.text.TextUtils;
import com.google.android.gms.iid.InstanceID;
import java.io.IOException;
import java.util.regex.Pattern;
import static org.microg.gms.gcm.GcmConstants.EXTRA_TOPIC;
/**
* GcmPubSub provides a publish-subscribe model for sending GCM topic messages.
* <p/>
* An app can subscribe to different topics defined by the
* developer. The app server can then send messages to the subscribed devices
* without having to maintain topic-subscribers mapping. Topics do not
* need to be explicitly created before subscribing or publishingthey
* are automatically created when publishing or subscribing.
* <pre>
* String topic = "/topics/myTopic";
* String registrationToken = InstanceID.getInstance(context)
* .getToken(SENDER_ID, GoogleCloudMessaging.INSTANCE_ID_SCOPE, null);
* GcmPubSub.getInstance(context).subscribe(registrationToken, topic, null);
* // Messages published to the topic will be received as regular GCM messages
* // with 'from' set to "/topics/myTopic"</pre>
* To publish to a topic, see
* <a href="https://developer.android.com/google/gcm/server.html">GCM server documentation</a>.
*/
public class GcmPubSub {
private static final Pattern topicPattern = Pattern.compile("/topics/[a-zA-Z0-9-_.~%]{1,900}");
private static GcmPubSub INSTANCE;
private final InstanceID instanceId;
public GcmPubSub(Context context) {
this.instanceId = InstanceID.getInstance(context);
}
/**
* Returns an instance of GCM PubSub.
*
* @return GcmPubSub instance
*/
public static synchronized GcmPubSub getInstance(Context context) {
if (INSTANCE == null) {
INSTANCE = new GcmPubSub(context);
}
return INSTANCE;
}
/**
* Subscribes an app instance to a topic, enabling it to receive messages
* sent to that topic.
* <p/>
* The topic sender must be authorized to send messages to the
* app instance. To authorize it, call {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}
* with the sender ID and {@link com.google.android.gms.gcm.GoogleCloudMessaging#INSTANCE_ID_SCOPE}
* <p/>
* Do not call this function on the main thread.
*
* @param registrationToken {@link com.google.android.gms.iid.InstanceID} token that authorizes topic
* sender to send messages to the app instance.
* @param topic developer defined topic name.
* Must match the following regular expression:
* "/topics/[a-zA-Z0-9-_.~%]{1,900}".
* @param extras (optional) additional information.
* @throws IOException if the request fails.
*/
public void subscribe(String registrationToken, String topic, Bundle extras) throws IOException {
if (TextUtils.isEmpty(registrationToken))
throw new IllegalArgumentException("No registration token!");
if (TextUtils.isEmpty(topic) || !topicPattern.matcher(topic).matches())
throw new IllegalArgumentException("Invalid topic: " + topic);
if (extras == null) extras = new Bundle();
extras.putString(EXTRA_TOPIC, topic);
instanceId.getToken(registrationToken, topic, extras);
}
/**
* Unsubscribes an app instance from a topic, stopping it from receiving
* any further messages sent to that topic.
* <p/>
* Do not call this function on the main thread.
*
* @param registrationToken {@link com.google.android.gms.iid.InstanceID} token
* for the same sender and scope that was previously
* used for subscribing to the topic.
* @param topic from which to stop receiving messages.
* @throws IOException if the request fails.
*/
public void unsubscribe(String registrationToken, String topic) throws IOException {
if (TextUtils.isEmpty(topic) || !topicPattern.matcher(topic).matches())
throw new IllegalArgumentException("Invalid topic: " + topic);
Bundle extras = new Bundle();
extras.putString(EXTRA_TOPIC, topic);
instanceId.deleteToken(registrationToken, topic, extras);
}
}

View file

@ -1,127 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.Manifest;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.os.Build;
import android.support.v4.content.WakefulBroadcastReceiver;
import android.util.Base64;
import android.util.Log;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;
import static org.microg.gms.gcm.GcmConstants.ACTION_INSTANCE_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;
import static org.microg.gms.gcm.GcmConstants.EXTRA_RAWDATA;
import static org.microg.gms.gcm.GcmConstants.EXTRA_RAWDATA_BASE64;
import static org.microg.gms.gcm.GcmConstants.GCMID_INSTANCE_ID;
import static org.microg.gms.gcm.GcmConstants.GCMID_REFRESH;
/**
* <code>WakefulBroadcastReceiver</code> that receives GCM messages and delivers them to an
* application-specific {@link com.google.android.gms.gcm.GcmListenerService} subclass.
* <p/>
* This receiver should be declared in your application's manifest file as follows:
* <p/>
* <pre>
* <receiver
* android:name="com.google.android.gms.gcm.GcmReceiver"
* android:exported="true"
* android:permission="com.google.android.c2dm.permission.SEND" >
* <intent-filter>
* <action android:name="com.google.android.c2dm.intent.RECEIVE" />
* <action android:name="com.google.android.c2dm.intent.REGISTRATION" />
* <category android:name="YOUR_PACKAGE_NAME" />
* </intent-filter>
* </receiver></pre>
* The <code>com.google.android.c2dm.permission.SEND</code> permission is held by Google Play
* services. This prevents other apps from invoking the broadcast receiver.
*/
public class GcmReceiver extends WakefulBroadcastReceiver {
private static final String TAG = "GcmReceiver";
public void onReceive(Context context, Intent intent) {
sanitizeIntent(context, intent);
enforceIntentClassName(context, intent);
sendIntent(context, intent);
if (getResultCode() == 0) setResultCodeIfOrdered(-1);
}
private void sanitizeIntent(Context context, Intent intent) {
intent.setComponent(null);
intent.setPackage(context.getPackageName());
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
intent.removeCategory(context.getPackageName());
}
String from = intent.getStringExtra(EXTRA_FROM);
if (ACTION_C2DM_REGISTRATION.equals(intent.getAction()) || GCMID_INSTANCE_ID.equals(from) || GCMID_REFRESH.equals(from)) {
intent.setAction(ACTION_INSTANCE_ID);
}
String base64encoded = intent.getStringExtra(EXTRA_RAWDATA_BASE64);
if (base64encoded != null) {
intent.putExtra(EXTRA_RAWDATA, Base64.decode(base64encoded, Base64.DEFAULT));
intent.removeExtra(EXTRA_RAWDATA_BASE64);
}
}
private void enforceIntentClassName(Context context, Intent intent) {
ResolveInfo resolveInfo = context.getPackageManager().resolveService(intent, 0);
if (resolveInfo == null || resolveInfo.serviceInfo == null) {
Log.e(TAG, "Failed to resolve target intent service, skipping classname enforcement");
return;
}
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
if (!context.getPackageName().equals(serviceInfo.packageName) || serviceInfo.name == null) {
Log.e(TAG, "Error resolving target intent service, skipping classname enforcement. Resolved service was: " + serviceInfo.packageName + "/" + serviceInfo.name);
return;
}
intent.setClassName(context, serviceInfo.name.startsWith(".") ? (context.getPackageName() + serviceInfo.name) : serviceInfo.name);
}
private void sendIntent(Context context, Intent intent) {
setResultCodeIfOrdered(500);
try {
ComponentName startedComponent;
if (context.checkCallingOrSelfPermission(Manifest.permission.WAKE_LOCK) == PackageManager.PERMISSION_GRANTED) {
startedComponent = startWakefulService(context, intent);
} else {
Log.d(TAG, "Missing wake lock permission, service start may be delayed");
startedComponent = context.startService(intent);
}
if (startedComponent == null) {
Log.e(TAG, "Error while delivering the message: ServiceIntent not found.");
setResultCodeIfOrdered(404);
} else {
setResultCodeIfOrdered(-1);
}
} catch (SecurityException e) {
Log.e(TAG, "Error while delivering the message to the serviceIntent", e);
setResultCodeIfOrdered(401);
}
}
private void setResultCodeIfOrdered(int code) {
if (isOrderedBroadcast()) {
setResultCode(code);
}
}
}

View file

@ -1,149 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.app.Service;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Parcelable;
import android.os.PowerManager;
import android.util.Log;
import org.microg.gms.common.PublicApi;
import org.microg.gms.gcm.GcmConstants;
/**
* Implemented by the client application to provide an endpoint for the {@link com.google.android.gms.gcm.GcmNetworkManager}
* to call back to when a task is ready to be executed.
* <p/>
* Clients must add this service to their manifest and implement
* {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}.
* This service must provide an {@link IntentFilter} on the action
* {@link com.google.android.gms.gcm.GcmTaskService#SERVICE_ACTION_EXECUTE_TASK}. Here's an example:
* <pre>
* <service android:name="MyTaskService"
* android:permission="com.google.android.gms.permission.BIND_NETWORK_TASK_SERVICE"
* android:exported="true">
* <intent-filter>
* <action android:name="com.google.android.gms.gcm.ACTION_TASK_READY"/>
* </intent-filter>
* </service>
* </pre>
* The return value of onRunTask(TaskParams) will determine what the manager does with subsequent
* executions of this task. Specifically you can return {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_RESCHEDULE}
* to have this task be re-executed again shortly subject to exponential back-off. Returning
* {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_FAILURE} for a periodic task will only affect the executing
* instance of the task, and future tasks will be executed as normal.
* <p/>
* Once a task is running it will not be cancelled, however a newly scheduled task with the same
* tag will not be executed until the active task has completed. This newly scheduled task will
* replace the previous task, regardless of whether the previous task returned
* {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_RESCHEDULE}.
* <p/>
* Bear in mind that your service may receive multiple calls from the scheduler at once
* (specifically if you've made multiple schedule requests that overlap). If this is the case, your
* implementation of {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)} must be thread-safe.
* <p/>
* The scheduler will hold a {@link PowerManager.WakeLock} for your service, however
* <strong>after three minutes of execution if your task has not returned it will be considered to
* have timed out, and the wakelock will be released.</strong> Rescheduling your task at this point
* will have no effect.
* If you suspect your task will run longer than this you should start your own service
* explicitly or use some other mechanism; this API is intended for relatively quick network
* operations.
* <p/>
* Your task will run at priority Process.THREAD_PRIORITY_BACKGROUND. If this
* is not appropriate, you should start your own service with suitably
* conditioned threads.
*/
@PublicApi
public abstract class GcmTaskService extends Service {
private static final String TAG = "GcmTaskService";
/**
* Action broadcast by the GcmNetworkManager to the requesting package when
* a scheduled task is ready for execution.
*/
public static final String SERVICE_ACTION_EXECUTE_TASK = GcmConstants.ACTION_TASK_READY;
/**
* Action that a {@link com.google.android.gms.gcm.GcmTaskService} is started with when the service needs to initialize
* its tasks.
*/
public static final String SERVICE_ACTION_INITIALIZE = GcmConstants.ACTION_TASK_INITIALZE;
/**
* You must protect your service with this permission to avoid being bound to by an
* application other than Google Play Services.
*/
public static final String SERVICE_PERMISSION = GcmConstants.PERMISSION_NETWORK_TASK;
public IBinder onBind(Intent intent) {
return null;
}
/**
* When your package is removed or updated, all of its network tasks are cleared by the
* GcmNetworkManager. You can override this method to reschedule them in the case of an
* updated package. This is not called when your application is first installed.
* <p/>
* This is called on your application's main thread.
*/
public void onInitializeTasks() {
// To be overwritten
}
/**
* Override this function to provide the logic for your task execution.
*
* @param params Parameters provided at schedule time with
* {@link com.google.android.gms.gcm.OneoffTask.Builder#setTag(java.lang.String)}
* @return One of {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_SUCCESS},
* {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_RESCHEDULE}, or
* {@link com.google.android.gms.gcm.GcmNetworkManager#RESULT_FAILURE}.
*/
public abstract int onRunTask(TaskParams params);
/**
* Receives the command to begin doing work, for which it spawns another thread.
*/
public int onStartCommand(Intent intent, int flags, int startId) {
intent.setExtrasClassLoader(PendingCallback.class.getClassLoader());
if (SERVICE_ACTION_EXECUTE_TASK.equals(intent.getAction())) {
String tag = intent.getStringExtra("tag");
Parcelable callback = intent.getParcelableExtra("callback");
Bundle extras = intent.getBundleExtra("extras");
if (callback == null || !(callback instanceof PendingCallback)) {
Log.w(TAG, tag + ": Invalid callback!");
return START_NOT_STICKY;
}
// TODO ensure single instance
// TODO run task in new thread
} else if (SERVICE_ACTION_INITIALIZE.equals(intent.getAction())) {
this.onInitializeTasks();
// TODO ensure single instance
}
return START_NOT_STICKY;
}
}

View file

@ -1,322 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.os.Looper;
import android.text.TextUtils;
import com.google.android.gms.iid.InstanceID;
import org.microg.gms.common.PublicApi;
import org.microg.gms.gcm.CloudMessagingRpc;
import org.microg.gms.gcm.GcmConstants;
import java.io.IOException;
import static org.microg.gms.common.Constants.GMS_PACKAGE_NAME;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_RECEIVE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_DELAY;
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_MESSAGE_TYPE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SENDER;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SENDER_LEGACY;
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;
/**
* GoogleCloudMessaging (GCM) enables apps to communicate with their app servers
* using simple messages.
* <p/>
* To send or receive messages, the app must get a
* registrationToken from {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}, which authorizes an
* app server to send messages to an app instance. Pass sender ID and
* {@link com.google.android.gms.gcm.GoogleCloudMessaging#INSTANCE_ID_SCOPE} as parameters to the method.
* A sender ID is a project number acquired from the API console, as described in
* <a href="http://developer.android.com/google/gcm/gs.html">Getting Started</a>.
* <p/>
* In order to receive GCM messages, declare {@link com.google.android.gms.gcm.GcmReceiver}
* and an implementation of {@link com.google.android.gms.gcm.GcmListenerService} in the app manifest.
* {@link com.google.android.gms.gcm.GcmReceiver} will pass the incoming messages to the implementation
* of {@link com.google.android.gms.gcm.GcmListenerService}. To process messages, override base class
* methods to handle any events required by the application.
* <p/>
* Client apps can send upstream messages back to the app server using the XMPP-based
* <a href="http://developer.android.com/google/gcm/ccs.html">Cloud Connection Server</a>,
* For example:
* <p/>
* gcm.send(SENDER_ID + "@gcm.googleapis.com", id, data);</pre>
* See <a href="https://developers.google.com/cloud-messaging/android/client">Implementing GCM Client on Android</a> for more details.
*/
@PublicApi
public class GoogleCloudMessaging {
/**
* The GCM {@link com.google.android.gms.gcm.GoogleCloudMessaging#register(java.lang.String...)} and {@link com.google.android.gms.gcm.GoogleCloudMessaging#unregister()} methods are
* blocking. Blocking methods must not be called on the main thread.
*/
public static final String ERROR_MAIN_THREAD = "MAIN_THREAD";
/**
* The device can't read the response, or there was a 500/503 from the
* server that can be retried later. The application should use exponential
* back off and retry.
*/
public static final String ERROR_SERVICE_NOT_AVAILABLE = GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;
/**
* Specifies scope used in obtaining GCM registrationToken when calling
* {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}
*/
public static final String INSTANCE_ID_SCOPE = GcmConstants.INSTANCE_ID_SCOPE_GCM;
/**
* Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate that the server deleted
* some pending messages because they exceeded the storage limits. The
* application should contact the server to retrieve the discarded messages.
*
* @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onDeletedMessages()}
*/
@Deprecated
public static final String MESSAGE_TYPE_DELETED = GcmConstants.MESSAGE_TYPE_DELETED_MESSAGE;
/**
* Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate a regular message.
*
* @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onMessageReceived(java.lang.String, android.os.Bundle)}
*/
@Deprecated
public static final String MESSAGE_TYPE_MESSAGE = GcmConstants.MESSAGE_TYPE_GCM;
/**
* Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate a send error.
* The intent includes the message ID of the message and an error code.
*
* @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onSendError(java.lang.String, java.lang.String)}
*/
@Deprecated
public static final String MESSAGE_TYPE_SEND_ERROR = GcmConstants.MESSAGE_TYPE_SEND_ERROR;
/**
* Returned by {@link com.google.android.gms.gcm.GoogleCloudMessaging#getMessageType(android.content.Intent)} to indicate a sent message has been received by the GCM
* server. The intent includes the message ID of the message.
*
* @deprecated Instead implement {@link com.google.android.gms.gcm.GcmListenerService#onMessageSent(java.lang.String)}
*/
@Deprecated
public static final String MESSAGE_TYPE_SEND_EVENT = GcmConstants.MESSAGE_TYPE_SEND_EVENT;
private static GoogleCloudMessaging instance;
private CloudMessagingRpc rpc;
private Context context;
public GoogleCloudMessaging() {
}
/**
* Must be called when your application is done using GCM, to release
* internal resources.
*/
public synchronized void close() {
instance = null;
rpc.close();
}
/**
* Return the singleton instance of GCM.
*/
public static GoogleCloudMessaging getInstance(Context context) {
if (instance == null) {
instance = new GoogleCloudMessaging();
instance.context = context.getApplicationContext();
instance.rpc = new CloudMessagingRpc(instance.context);
}
return instance;
}
/**
* Return the message type from an intent passed into a client app's broadcast receiver. There
* are two general categories of messages passed from the server: regular GCM messages,
* and special GCM status messages.
* <p/>
* The possible types are:
* {@link #MESSAGE_TYPE_MESSAGE}, {@link #MESSAGE_TYPE_DELETED}, {@link #MESSAGE_TYPE_SEND_EVENT} and {@link #MESSAGE_TYPE_SEND_ERROR}
* <p/>
* You can use this method to filter based on message type. Since it is likely that GCM will
* be extended in the future with new message types, just ignore any message types you're not
* interested in, or that you don't recognize.
*
* @return The message type or null if the intent is not a GCM intent
*/
public String getMessageType(Intent intent) {
if (intent == null || !ACTION_C2DM_RECEIVE.equals(intent.getAction())) return null;
if (!intent.hasExtra(EXTRA_MESSAGE_TYPE)) return MESSAGE_TYPE_MESSAGE;
return intent.getStringExtra(EXTRA_MESSAGE_TYPE);
}
/**
* Register the application for GCM and return the registration ID. You must call this once,
* when your application is installed, and send the returned registration ID to the server.
* <p/>
* Repeated calls to this method will return the original registration ID.
* <p/>
* If you want to modify the list of senders, you must call <code>unregister()</code> first.
* <p/>
* Most applications use a single sender ID. You may use multiple senders if different
* servers may send messages to the app or for testing.</p>
*
* @param senderIds list of project numbers or Google accounts identifying who is allowed to
* send messages to this application.
* @return registration id
* @throws IOException
* @deprecated Instead, for GCM registration, use
* {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}.
* Set authorizedEntity to a sender ID and scope to {@link com.google.android.gms.gcm.GoogleCloudMessaging#INSTANCE_ID_SCOPE}.
*/
@Deprecated
public String register(String... senderIds) throws IOException {
if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);
if (senderIds == null || senderIds.length == 0) throw new IllegalArgumentException("No sender ids");
StringBuilder sb = new StringBuilder(senderIds[0]);
for (int i = 1; i < senderIds.length; i++) {
sb.append(',').append(senderIds[i]);
}
String sender = sb.toString();
if (isLegacyFallback()) {
Bundle extras = new Bundle();
extras.putString(EXTRA_SENDER_LEGACY, sender);
return InstanceID.getInstance(context).getToken(sb.toString(), INSTANCE_ID_SCOPE, extras);
} else {
Bundle extras = new Bundle();
extras.putString(EXTRA_SENDER, sender);
return rpc.handleRegisterMessageResult(rpc.sendRegisterMessageBlocking(extras));
}
}
/**
* Send an upstream ("device to cloud") message. You can only use the upstream feature
* if your GCM implementation uses the XMPP-based
* <a href="http://developer.android.com/google/gcm/ccs.html">Cloud Connection Server</a>.
* <p/>
* The current limits for max storage time and number of outstanding messages per
* application are documented in the
* <a href="http://developer.android.com/google/gcm/index.html">GCM Developers Guide</a>.</p>
*
* @param to string identifying the receiver of the message in the format of
* <code>SENDER_ID@gcm.googleapis.com</code>. The <code>SENDER_ID</code> should be one of the sender
* IDs used when calling {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}
* @param msgId ID of the message. This is generated by the application. It must be
* unique for each message. This allows error callbacks and debugging.
* @param timeToLive If 0, we'll attempt to send immediately and return an
* error if we're not connected. Otherwise, the message will be queued.
* As for server-side messages, we don't return an error if the message has been
* dropped because of TTLthis can happen on the server side, and it would require
* extra communication.
* @param data key/value pairs to be sent. Values must be String, any other type will
* be ignored.
* @throws IllegalArgumentException
* @throws IOException
*/
public void send(String to, String msgId, long timeToLive, Bundle data) throws IOException {
if (TextUtils.isEmpty(to)) throw new IllegalArgumentException("Invalid 'to'");
if (isLegacyFallback()) {
Bundle extras = new Bundle();
for (String key : data.keySet()) {
Object o = extras.get(key);
if (o instanceof String) {
extras.putString("gcm." + key, (String) o);
}
}
extras.putString(EXTRA_SEND_TO, to);
extras.putString(EXTRA_MESSAGE_ID, msgId);
InstanceID.getInstance(context).requestToken("GCM", "upstream", extras);
} else {
Bundle extras = data != null ? new Bundle(data) : new Bundle();
extras.putString(EXTRA_SEND_TO, to);
extras.putString(EXTRA_SEND_FROM, getFrom(to));
extras.putString(EXTRA_MESSAGE_ID, msgId);
extras.putLong(EXTRA_TTL, timeToLive);
extras.putInt(EXTRA_DELAY, -1);
rpc.sendGcmMessage(extras);
}
}
/**
* Send an upstream ("device to cloud") message. You can only use the upstream feature
* if your GCM implementation uses the XMPP-based
* <a href="http://developer.android.com/google/gcm/ccs.html">Cloud Connection Server</a>.
* <p/>
* When there is an active connection the message will be sent immediately, otherwise the
* message will be queued for the maximum interval.
*
* @param to string identifying the receiver of the message in the format of
* <code>SENDER_ID@gcm.googleapis.com</code>. The <code>SENDER_ID</code> should be one of the sender
* IDs used when calling {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}
* @param msgId ID of the message. This is generated by the application. It must be
* unique for each message. This allows error callbacks and debugging.
* @param data key/value pairs to be sent. Values must be Stringany other type will
* be ignored.
* @throws IllegalArgumentException
* @throws IOException
*/
public void send(String to, String msgId, Bundle data) throws IOException {
send(to, msgId, -1, data);
}
/**
* Unregister the application. Calling <code>unregister()</code> stops any
* messages from the server. This is a blocking callyou shouldn't call
* it from the UI thread.
* <p/>
* You should rarely (if ever) need to call this method. Not only is it
* expensive in terms of resources, but it invalidates all your registration IDs
* returned from register() or subscribe(). This should not be done
* unnecessarily. A better approach is to simply have your server stop
* sending messages.
*
* @throws IOException if we can't connect to server to unregister.
* @deprecated Instead use
* {@link com.google.android.gms.iid.InstanceID#deleteToken(java.lang.String, java.lang.String)} or
* {@link com.google.android.gms.iid.InstanceID#deleteInstanceID()}.
*/
@Deprecated
public void unregister() throws IOException {
if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);
InstanceID.getInstance(context).deleteInstanceID();
}
private boolean isLegacyFallback() {
String gcmPackageName = CloudMessagingRpc.getGcmPackageName(context);
return gcmPackageName != null && gcmPackageName.endsWith(".gsf");
}
private String getFrom(String to) {
int i = to.indexOf('@');
if (i > 0) {
to = to.substring(0, i);
}
return InstanceID.getInstance(context).getStore().get("", to, INSTANCE_ID_SCOPE);
}
}

View file

@ -1,221 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.os.Bundle;
import android.os.Parcel;
import org.microg.gms.common.PublicApi;
/**
* A task that will execute once,at some point within the specified window.
* If one of {@link com.google.android.gms.gcm.GcmNetworkManager#cancelTask(java.lang.String, java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)} or
* {@link com.google.android.gms.gcm.GcmNetworkManager#cancelAllTasks(java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)} is called before this
* executes it will be cancelled.
* <p/>
* Note that you can request a one-off task to be executed at any point in the future, but to
* prevent abuse the scheduler will only set an alarm at a minimum of 30 seconds in the
* future. Your task can still be run earlier than this if some network event occurs to wake up
* the scheduler.
*/
@PublicApi
public class OneoffTask extends com.google.android.gms.gcm.Task {
private final long windowStart;
private final long windowEnd;
private OneoffTask(Builder builder) {
super(builder);
this.windowStart = builder.windowStart;
this.windowEnd = builder.windowEnd;
}
private OneoffTask(Parcel source) {
super(source);
this.windowStart = source.readLong();
this.windowEnd = source.readLong();
}
/**
* @return The number of seconds from now by which this task must have executed.
*/
public long getWindowEnd() {
return windowEnd;
}
/**
* @return The number of seconds from now at which this task is eligible for execution.
*/
public long getWindowStart() {
return windowStart;
}
/**
* Insert the task object into the provided bundle for IPC. Use #fromBundle to recreate the
* object on the other side.
*/
public void toBundle(Bundle bundle) {
super.toBundle(bundle);
bundle.putLong("window_start", this.windowStart);
bundle.putLong("window_end", this.windowEnd);
}
public String toString() {
return super.toString()
+ " windowStart=" + this.getWindowStart()
+ " windowEnd=" + this.getWindowEnd();
}
public void writeToParcel(Parcel parcel, int flags) {
super.writeToParcel(parcel, flags);
parcel.writeLong(this.windowStart);
parcel.writeLong(this.windowEnd);
}
public static final Creator<OneoffTask> CREATOR = new Creator<OneoffTask>() {
@Override
public OneoffTask createFromParcel(Parcel source) {
return new OneoffTask(source);
}
@Override
public OneoffTask[] newArray(int size) {
return new OneoffTask[size];
}
};
public static class Builder extends Task.Builder {
private long windowStart = -1;
private long windowEnd = -1;
public Builder() {
this.isPersisted = false;
}
public OneoffTask build() {
return new OneoffTask(this);
}
/**
* Mandatory setter for creating a one-off task. You specify the earliest point in
* time in the future from which your task might start executing, as well as the
* latest point in time in the future at which your task must have executed.
*
* @param windowStartDelaySeconds Earliest point from which your task is eligible to
* run.
* @param windowEndDelaySeconds Latest point at which your task must be run.
*/
public OneoffTask.Builder setExecutionWindow(long windowStartDelaySeconds, long windowEndDelaySeconds) {
this.windowEnd = windowEndDelaySeconds;
this.windowStart = windowStartDelaySeconds;
return this;
}
/**
* Optional setter for specifying any extra parameters necessary for the task.
*/
public OneoffTask.Builder setExtras(Bundle extras) {
this.extras = extras;
return this;
}
/**
* Optional setter to specify whether this task should be persisted across reboots..
* Callers <strong>must</strong> hold the permission
* android.Manifest.permission.RECEIVE_BOOT_COMPLETED, otherwise this setter is
* ignored.
*
* @param isPersisted True if this task should be persisted across device reboots.
*/
public OneoffTask.Builder setPersisted(boolean isPersisted) {
this.isPersisted = isPersisted;
return this;
}
/**
* Set the network state your task requires to run. <strong>If the specified network is
* unavailable your task will not be executed until it becomes available.</strong>
* <p/>
* The default for either a periodic or one-off task is
* {@link com.google.android.gms.gcm.Task#NETWORK_STATE_CONNECTED}. Note that changing this to
* {@link com.google.android.gms.gcm.Task#NETWORK_STATE_ANY} means there is no guarantee that data will be available
* when your task executes.
* <p/>
* In addition, the only guarantee for connectivity is at the moment of execution - it is
* possible for the device to lose data shortly after your task begins executing.
*/
public OneoffTask.Builder setRequiredNetwork(int requiredNetworkState) {
this.requiredNetworkState = requiredNetworkState;
return this;
}
/**
* Set whether your task requires that the device be connected to power in order to
* execute.
* <p/>
* Use this to defer nonessential operations whenever possible. Note that if you set this
* field and the device is not connected to power <strong>your task will not run</strong>
* until the device is plugged in.
* <p/>
* One way to deal with your task not executing until the constraint is met is to schedule
* another task without the constraints that is subject to some deadline that you can abide.
* This task would be responsible for executing your fallback logic.
*/
public OneoffTask.Builder setRequiresCharging(boolean requiresCharging) {
this.requiresCharging = requiresCharging;
return this;
}
/**
* Set whichever {@link com.google.android.gms.gcm.GcmTaskService} you implement to execute the logic for this task.
*
* @param gcmTaskService Endpoint against which you're scheduling this task.
*/
public OneoffTask.Builder setService(Class<? extends GcmTaskService> gcmTaskService) {
this.gcmTaskService = gcmTaskService.getName();
return this;
}
/**
* Mandatory setter for specifying the tag identifer for this task. This tag will be
* returned at execution time to your endpoint. See
* {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}
* Maximum tag length is 100.<
*
* @param tag String identifier for this task. Consecutive schedule calls for the same
* tag will update any preexisting task with the same tag.
*/
public OneoffTask.Builder setTag(String tag) {
this.tag = tag;
return this;
}
/**
* Optional setter to specify whether this task should override any preexisting tasks
* with the same tag. This defaults to false, which means that a new task will not
* override an existing one.
*
* @param updateCurrent True to update the current task with the parameters of the new.
* Default false.
*/
public OneoffTask.Builder setUpdateCurrent(boolean updateCurrent) {
this.updateCurrent = updateCurrent;
return this;
}
}
}

View file

@ -1,59 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.os.IBinder;
import android.os.Parcel;
import android.os.Parcelable;
public class PendingCallback implements Parcelable {
private final IBinder binder;
public PendingCallback(IBinder binder) {
this.binder = binder;
}
private PendingCallback(Parcel in) {
this.binder = in.readStrongBinder();
}
public IBinder getBinder() {
return binder;
}
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStrongBinder(binder);
}
public static final Creator<PendingCallback> CREATOR = new Creator<PendingCallback>() {
@Override
public PendingCallback createFromParcel(Parcel source) {
return new PendingCallback(source);
}
@Override
public PendingCallback[] newArray(int size) {
return new PendingCallback[size];
}
};
}

View file

@ -1,235 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.os.Bundle;
import android.os.Parcel;
import org.microg.gms.common.PublicApi;
/**
* A periodic task is one that will recur at the specified interval, without needing to be
* rescheduled.
* Schedule a task that will recur until the user calls one of
* {@link com.google.android.gms.gcm.GcmNetworkManager#cancelAllTasks(java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)}, or
* {@link com.google.android.gms.gcm.GcmNetworkManager#cancelTask(java.lang.String, java.lang.Class<? extends com.google.android.gms.gcm.GcmTaskService>)} with
* an identifying tag.
* <p/>
* Periodic tasks will not be scheduled if their period is below a certain minimum
* (currently 30 seconds).
*/
@PublicApi
public class PeriodicTask extends com.google.android.gms.gcm.Task {
protected long mFlexInSeconds;
protected long mIntervalInSeconds;
private PeriodicTask(Builder builder) {
super(builder);
this.mIntervalInSeconds = builder.periodInSeconds;
this.mFlexInSeconds = Math.min(builder.flexInSeconds, mIntervalInSeconds);
}
private PeriodicTask(Parcel source) {
super(source);
mIntervalInSeconds = source.readLong();
mFlexInSeconds = Math.min(source.readLong(), mIntervalInSeconds);
}
/**
* @return The number of seconds before the end of the period returned via
* {@link com.google.android.gms.gcm.PeriodicTask#getPeriod()} that this periodic task can be executed early.
*/
public long getFlex() {
return mFlexInSeconds;
}
/**
* @return The period for this task. The number of seconds between subsequent executions.
*/
public long getPeriod() {
return mIntervalInSeconds;
}
/**
* Insert the task object into the provided bundle for IPC. Use #fromBundle to recreate the
* object on the other side.
*/
public void toBundle(Bundle bundle) {
super.toBundle(bundle);
bundle.putLong("period", this.mIntervalInSeconds);
bundle.putLong("period_flex", this.mFlexInSeconds);
}
public String toString() {
return super.toString() + " period=" + this.getPeriod() + " flex=" + this.getFlex();
}
public void writeToParcel(Parcel parcel, int flags) {
super.writeToParcel(parcel, flags);
parcel.writeLong(this.mIntervalInSeconds);
parcel.writeLong(this.mFlexInSeconds);
}
public static final Creator<PeriodicTask> CREATOR = new Creator<PeriodicTask>() {
@Override
public PeriodicTask createFromParcel(Parcel source) {
return new PeriodicTask(source);
}
@Override
public PeriodicTask[] newArray(int size) {
return new PeriodicTask[size];
}
};
public static class Builder extends com.google.android.gms.gcm.Task.Builder {
private long flexInSeconds = -1;
private long periodInSeconds = -1;
public Builder() {
isPersisted = true;
}
public PeriodicTask build() {
return new PeriodicTask(this);
}
/**
* Optional setter for specifying any extra parameters necessary for the task.
*/
public PeriodicTask.Builder setExtras(Bundle extras) {
this.extras = extras;
return this;
}
/**
* Optional setter for specifying how close to the end of the period set in
* {@link com.google.android.gms.gcm.PeriodicTask.Builder#setPeriod(long)} you are willing to execute.
* <p/>
* For example, specifying a period of 30 seconds, with a flex value of 10 seconds
* will allow the scheduler to determine the best moment between the 20th and 30th
* second at which to execute your task.
*/
public PeriodicTask.Builder setFlex(long flexInSeconds) {
this.flexInSeconds = flexInSeconds;
return this;
}
/**
* Mandatory setter for creating a periodic task. This specifies that you would like
* this task to recur at most once every <code>mIntervalInSeconds.</code>
* <p/>
* By default you have no control over where within this period the task will execute.
* If you want to restrict the task to run within a certain timeframe from the end of
* the period, use {@link com.google.android.gms.gcm.PeriodicTask.Builder#setFlex(long)}
*/
public PeriodicTask.Builder setPeriod(long periodInSeconds) {
this.periodInSeconds = periodInSeconds;
return this;
}
/**
* Optional setter to specify whether this task should be persisted across reboots. This
* defaults to true for periodic tasks,
* <p/>
* Callers <strong>must</strong> hold the permission
* android.Manifest.permission.RECEIVE_BOOT_COMPLETED, otherwise this setter is
* ignored.
*
* @param isPersisted True if this task should be persisted across device reboots.
*/
public PeriodicTask.Builder setPersisted(boolean isPersisted) {
this.isPersisted = isPersisted;
return this;
}
/**
* Set the network state your task requires to run. <strong>If the specified network is
* unavailable your task will not be executed until it becomes available.</strong>
* <p/>
* The default for either a periodic or one-off task is
* {@link com.google.android.gms.gcm.Task#NETWORK_STATE_CONNECTED}. Note that changing this to
* {@link com.google.android.gms.gcm.Task#NETWORK_STATE_ANY} means there is no guarantee that data will be available
* when your task executes.
* <p/>
* In addition, the only guarantee for connectivity is at the moment of execution - it is
* possible for the device to lose data shortly after your task begins executing.
*/
public PeriodicTask.Builder setRequiredNetwork(int requiredNetworkState) {
this.requiredNetworkState = requiredNetworkState;
return this;
}
/**
* Set whether your task requires that the device be connected to power in order to
* execute.
* <p/>
* Use this to defer nonessential operations whenever possible. Note that if you set this
* field and the device is not connected to power <strong>your task will not run</strong>
* until the device is plugged in.
* <p/>
* One way to deal with your task not executing until the constraint is met is to schedule
* another task without the constraints that is subject to some deadline that you can abide.
* This task would be responsible for executing your fallback logic.
*/
public PeriodicTask.Builder setRequiresCharging(boolean requiresCharging) {
this.requiresCharging = requiresCharging;
return this;
}
/**
* <p>Set whichever {@link com.google.android.gms.gcm.GcmTaskService} you implement to execute the logic for this task.</p>
*
* @param gcmTaskService Endpoint against which you're scheduling this task.
*/
public PeriodicTask.Builder setService(Class<? extends GcmTaskService> gcmTaskService) {
this.gcmTaskService = gcmTaskService.getName();
return this;
}
/**
* Mandatory setter for specifying the tag identifer for this task. This tag will be
* returned at execution time to your endpoint. See
* {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}
* <p/>
* Maximum tag length is 100.
*
* @param tag String identifier for this task. Consecutive schedule calls for the same
* tag will update any preexisting task with the same tag.
*/
public PeriodicTask.Builder setTag(String tag) {
this.tag = tag;
return this;
}
/**
* Optional setter to specify whether this task should override any preexisting tasks
* with the same tag. This defaults to false, which means that a new task will not
* override an existing one.
*
* @param updateCurrent True to update the current task with the parameters of the new.
* Default false.
*/
public PeriodicTask.Builder setUpdateCurrent(boolean updateCurrent) {
this.updateCurrent = updateCurrent;
return this;
}
}
}

View file

@ -1,271 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.os.Bundle;
import android.os.Parcel;
import android.os.Parcelable;
import org.microg.gms.common.PublicApi;
/**
* Encapsulates the parameters of a task that you will schedule on the
* {@link com.google.android.gms.gcm.GcmNetworkManager}.
* <p/>
* Construct instances of either {@link com.google.android.gms.gcm.PeriodicTask} or
* {@link com.google.android.gms.gcm.OneoffTask} with the desired parameters/behaviour and
* schedule them using {@link com.google.android.gms.gcm.GcmNetworkManager#schedule(com.google.android.gms.gcm.Task)}.
*/
@PublicApi
public abstract class Task implements Parcelable {
/**
* <p>The maximum size allowed for extras bundle in bytes.
* </p>
*/
public static final int EXTRAS_LIMIT_BYTES = 10240;
/**
* <p>Specify using {@link com.google.android.gms.gcm.Task.Builder#setRequiredNetwork(int)}
* that your task will execute [...] of whether network is available.
* </p>
*/
public static final int NETWORK_STATE_ANY = 2;
/**
* <p>Specify using {@link com.google.android.gms.gcm.Task.Builder#setRequiredNetwork(int)}
* that your task will only execute if [...] sort of data connection is available -
* either metered or unmetered. <strong>This is the default.</strong></p>
*/
public static final int NETWORK_STATE_CONNECTED = 0;
/**
* <p>Specify using {@link com.google.android.gms.gcm.Task.Builder#setRequiredNetwork(int)}
* that your task will only execute if there is an unmetered network connection available.
* </p>
*/
public static final int NETWORK_STATE_UNMETERED = 1;
protected static final long UNINITIALIZED = -1;
private final String serviceName;
private final String tag;
private final boolean updateCurrent;
private final boolean persisted;
private final int requiredNetwork;
private final boolean requiresCharging;
private final Bundle extras;
Task(Builder builder) {
this.serviceName = builder.gcmTaskService;
this.tag = builder.tag;
this.updateCurrent = builder.updateCurrent;
this.persisted = builder.isPersisted;
this.requiredNetwork = builder.requiredNetworkState;
this.requiresCharging = builder.requiresCharging;
this.extras = builder.extras;
}
Task(Parcel in) {
this.serviceName = in.readString();
this.tag = in.readString();
this.updateCurrent = in.readInt() == 1;
this.persisted = in.readInt() == 1;
this.requiredNetwork = NETWORK_STATE_ANY;
this.requiresCharging = false;
this.extras = null;
}
public int describeContents() {
return 0;
}
/**
* @return The extra parameters for the task set by the client.
*/
public Bundle getExtras() {
return extras;
}
/**
* If the specified network is unavailable, your task <strong>will not be run</strong> until
* it is.
*
* @return The network type that this task requires in order to run. See the NETWORK_TYPE_*
* flavours for an explanation of what this value can be.
*/
public int getRequiredNetwork() {
return requiredNetwork;
}
/**
* If the device is not charging and this is set to true, your task <strong>will not be run
* </strong> until it is.
*
* @return Whether or not this task depends on the device being connected to power in order to
* execute.
*/
public boolean getRequiresCharging() {
return requiresCharging;
}
/**
* @return The {@link com.google.android.gms.gcm.GcmTaskService} component that this task
* will execute on.
*/
public String getServiceName() {
return serviceName;
}
/**
* @return The String identifier for this task, that is returned to
* {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}
* when this task executes.
*/
public String getTag() {
return tag;
}
/**
* @return Whether this task will be persisted across devices restarts or Google Play Services
* crashes.
*/
public boolean isPersisted() {
return persisted;
}
/**
* @return Whether or not this task will update a pre-existing task in the scheduler queue.
*/
public boolean isUpdateCurrent() {
return updateCurrent;
}
public void toBundle(Bundle bundle) {
bundle.putString("tag", this.tag);
bundle.putBoolean("update_current", this.updateCurrent);
bundle.putBoolean("persisted", this.persisted);
bundle.putString("service", this.serviceName);
bundle.putInt("requiredNetwork", this.requiredNetwork);
bundle.putBoolean("requiresCharging", this.requiresCharging);
bundle.putBundle("retryStrategy", null); // TODO
bundle.putBundle("extras", this.extras);
}
public void writeToParcel(Parcel parcel, int i) {
parcel.writeString(serviceName);
parcel.writeString(tag);
parcel.writeInt(updateCurrent ? 1 : 0);
parcel.writeInt(persisted ? 1 : 0);
}
/**
* <p>Builder object to construct these tasks before sending them to the network manager. Use
* either {@link com.google.android.gms.gcm.PeriodicTask.Builder} or
* {@link com.google.android.gms.gcm.Task.Builder}</p>
*/
public abstract static class Builder {
protected Bundle extras;
protected String gcmTaskService;
protected boolean isPersisted;
protected int requiredNetworkState;
protected boolean requiresCharging;
protected String tag;
protected boolean updateCurrent;
public Builder() {
throw new UnsupportedOperationException();
}
public abstract Task build();
/**
* Optional setter for specifying any extra parameters necessary for the task.
*/
public abstract Task.Builder setExtras(Bundle extras);
/**
* Optional setter to specify whether this task should be persisted across reboots. This
* defaults to true for periodic tasks, and is not supported for one-off tasks.
* <p/>
* Callers <strong>must</strong> hold the permission
* android.Manifest.permission.RECEIVE_BOOT_COMPLETED, otherwise this setter is
* ignored.
*
* @param isPersisted True if this task should be persisted across device reboots.
*/
public abstract Task.Builder setPersisted(boolean isPersisted);
/**
* Set the network state your task requires to run. <strong>If the specified network is
* unavailable your task will not be executed until it becomes available.</strong>
* <p/>
* The default for either a periodic or one-off task is
* {@link com.google.android.gms.gcm.Task#NETWORK_STATE_CONNECTED}. Note that changing this to
* {@link com.google.android.gms.gcm.Task#NETWORK_STATE_ANY} means there is no guarantee that data will be available
* when your task executes.
* <p/>
* In addition, the only guarantee for connectivity is at the moment of execution - it is
* possible for the device to lose data shortly after your task begins executing.
*/
public abstract Task.Builder setRequiredNetwork(int requiredNetworkState);
/**
* Set whether your task requires that the device be connected to power in order to
* execute.
* <p/>
* Use this to defer nonessential operations whenever possible. Note that if you set this
* field and the device is not connected to power <strong>your task will not run</strong>
* until the device is plugged in.
* <p/>
* One way to deal with your task not executing until the constraint is met is to schedule
* another task without the constraints that is subject to some deadline that you can abide.
* This task would be responsible for executing your fallback logic.
*/
public abstract Task.Builder setRequiresCharging(boolean requiresCharging);
/**
* Set whichever {@link com.google.android.gms.gcm.GcmTaskService} you implement to execute the logic for this task.
*
* @param gcmTaskService Endpoint against which you're scheduling this task.
*/
public abstract Task.Builder setService(Class<? extends GcmTaskService> gcmTaskService);
/**
* Mandatory setter for specifying the tag identifer for this task. This tag will be
* returned at execution time to your endpoint. See
* {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}
* <p/>
* Maximum tag length is 100.
*
* @param tag String identifier for this task. Consecutive schedule calls for the same tag
* will update any preexisting task with the same tag.
*/
public abstract Task.Builder setTag(String tag);
/**
* Optional setter to specify whether this task should override any preexisting tasks with
* the same tag. This defaults to false, which means that a new task will not override an
* existing one.
*
* @param updateCurrent True to update the current task with the parameters of the new.
* Default false.
*/
public abstract Task.Builder setUpdateCurrent(boolean updateCurrent);
}
}

View file

@ -1,49 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.gcm;
import android.os.Bundle;
import org.microg.gms.common.PublicApi;
/**
* Container of parameters handed off to the client app in
* {@link com.google.android.gms.gcm.GcmTaskService#onRunTask(com.google.android.gms.gcm.TaskParams)}.
*/
@PublicApi
public class TaskParams {
private final String tag;
private final Bundle extras;
public TaskParams(String tag) {
this(tag, null);
}
public TaskParams(String tag, Bundle extras) {
this.tag = tag;
this.extras = extras;
}
public Bundle getExtras() {
return extras;
}
public String getTag() {
return tag;
}
}

View file

@ -1,165 +0,0 @@
/*
* Copyright (C) 2013-2017 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);
}
}

View file

@ -1,47 +0,0 @@
/*
* Copyright 2013-2015 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.
*/
apply plugin: 'com.android.library'
String getMyVersionName() {
def stdout = new ByteArrayOutputStream()
if (rootProject.file("gradlew").exists())
exec { commandLine 'git', 'describe', '--tags', '--always', '--dirty'; standardOutput = stdout }
else // automatic build system, don't tag dirty
exec { commandLine 'git', 'describe', '--tags', '--always'; standardOutput = stdout }
return stdout.toString().trim().substring(1)
}
android {
compileSdkVersion androidCompileSdk()
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName getMyVersionName()
minSdkVersion androidMinSdk()
targetSdkVersion androidTargetSdk()
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
dependencies {
api project(':play-services-base')
api project(':play-services-iid-api')
}

View file

@ -1,34 +0,0 @@
#
# 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.
#
POM_NAME=Play Services IID Library
POM_DESCRIPTION=The Play Services Library module to access the InstanceID API
POM_PACKAGING=aar
POM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=mar-v-in
POM_DEVELOPER_NAME=Marvin W

View file

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2013-2017 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.
-->
<manifest package="org.microg.gms.iid"
xmlns:android="http://schemas.android.com/apk/res/android">
<!-- Permissions required for IID -->
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE"/>
<uses-permission android:name="android.permission.INTERNET"/>
</manifest>

View file

@ -1,275 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.iid;
import android.content.Context;
import android.os.Bundle;
import android.os.Looper;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import org.microg.gms.common.PublicApi;
import org.microg.gms.gcm.GcmConstants;
import org.microg.gms.iid.InstanceIdRpc;
import org.microg.gms.iid.InstanceIdStore;
import java.io.IOException;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import static org.microg.gms.gcm.GcmConstants.EXTRA_DELETE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SCOPE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SENDER;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SUBSCIPTION;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SUBTYPE;
/**
* Instance ID provides a unique identifier for each app instance and a mechanism
* to authenticate and authorize actions (for example, sending a GCM message).
* <p/>
* Instance ID is stable but may become invalid, if:
* <ul>
* <li>App deletes Instance ID</li>
* <li>Device is factory reset</li>
* <li>User uninstalls the app</li>
* <li>User clears app data</li>
* </ul>
* If Instance ID has become invalid, the app can call {@link com.google.android.gms.iid.InstanceID#getId()}
* to request a new Instance ID.
* To prove ownership of Instance ID and to allow servers to access data or
* services associated with the app, call {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}.
*/
@PublicApi
public class InstanceID {
/**
* Error returned when failed requests are retried too often. Use
* exponential backoff when retrying requests
*/
public static final String ERROR_BACKOFF = "RETRY_LATER";
/**
* Blocking methods must not be called on the main thread.
*/
public static final String ERROR_MAIN_THREAD = "MAIN_THREAD";
/**
* Tokens can't be generated. Only devices with Google Play are supported.
*/
public static final String ERROR_MISSING_INSTANCEID_SERVICE = "MISSING_INSTANCEID_SERVICE";
/**
* The device cannot read the response, or there was a server error.
* Application should retry the request later using exponential backoff
* and retry (on each subsequent failure increase delay before retrying).
*/
public static final String ERROR_SERVICE_NOT_AVAILABLE = GcmConstants.ERROR_SERVICE_NOT_AVAILABLE;
/**
* Timeout waiting for a response.
*/
public static final String ERROR_TIMEOUT = "TIMEOUT";
private static final int RSA_KEY_SIZE = 2048;
private static final String TAG = "InstanceID";
private static InstanceIdStore storeInstance;
private static InstanceIdRpc rpc;
private static Map<String, InstanceID> instances = new HashMap<String, InstanceID>();
private final String subtype;
private KeyPair keyPair;
private long creationTime;
private InstanceID(String subtype) {
this.subtype = subtype == null ? "" : subtype;
}
/**
* Resets Instance ID and revokes all tokens.
*
* @throws IOException
*/
public void deleteInstanceID() throws IOException {
deleteToken("*", "*");
creationTime = 0;
storeInstance.delete(subtype + "|");
keyPair = null;
}
/**
* Revokes access to a scope (action) for an entity previously
* authorized by {@link com.google.android.gms.iid.InstanceID#getToken(java.lang.String, java.lang.String)}.
* <p/>
* Do not call this function on the main thread.
*
* @param authorizedEntity Entity that must no longer have access.
* @param scope Action that entity is no longer authorized to perform.
* @throws IOException if the request fails.
*/
public void deleteToken(String authorizedEntity, String scope) throws IOException {
deleteToken(authorizedEntity, scope, null);
}
@PublicApi(exclude = true)
public void deleteToken(String authorizedEntity, String scope, Bundle extras) throws IOException {
if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);
storeInstance.delete(subtype, authorizedEntity, scope);
if (extras == null) extras = new Bundle();
extras.putString(EXTRA_SENDER, authorizedEntity);
extras.putString(EXTRA_SUBSCIPTION, authorizedEntity);
extras.putString(EXTRA_DELETE, "1");
extras.putString("X-" + EXTRA_DELETE, "1");
extras.putString(EXTRA_SUBTYPE, TextUtils.isEmpty(subtype) ? authorizedEntity : subtype);
extras.putString("X-" + EXTRA_SUBTYPE, TextUtils.isEmpty(subtype) ? authorizedEntity : subtype);
if (scope != null) extras.putString(EXTRA_SCOPE, scope);
rpc.handleRegisterMessageResult(rpc.sendRegisterMessageBlocking(extras, getKeyPair()));
}
/**
* Returns time when instance ID was created.
*
* @return Time when instance ID was created (milliseconds since Epoch).
*/
public long getCreationTime() {
if (creationTime == 0) {
String s = storeInstance.get(subtype, "cre");
if (s != null) {
creationTime = Long.parseLong(s);
}
}
return creationTime;
}
/**
* Returns a stable identifier that uniquely identifies the app instance.
*
* @return The identifier for the application instance.
*/
public String getId() {
return sha1KeyPair(getKeyPair());
}
/**
* Returns an instance of this class.
*
* @return InstanceID instance.
*/
public static InstanceID getInstance(Context context) {
String subtype = "";
if (storeInstance == null) {
storeInstance = new InstanceIdStore(context.getApplicationContext());
rpc = new InstanceIdRpc(context.getApplicationContext());
}
InstanceID instance = instances.get(subtype);
if (instance == null) {
instance = new InstanceID(subtype);
instances.put(subtype, instance);
}
return instance;
}
/**
* Returns a token that authorizes an Entity (example: cloud service) to perform
* an action on behalf of the application identified by Instance ID.
* <p/>
* This is similar to an OAuth2 token except, it applies to the
* application instance instead of a user.
* <p/>
* Do not call this function on the main thread.
*
* @param authorizedEntity Entity authorized by the token.
* @param scope Action authorized for authorizedEntity.
* @param extras additional parameters specific to each token scope.
* Bundle keys starting with 'GCM.' and 'GOOGLE.' are
* reserved.
* @return a token that can identify and authorize the instance of the
* application on the device.
* @throws IOException if the request fails.
*/
public String getToken(String authorizedEntity, String scope, Bundle extras) throws IOException {
if (Looper.getMainLooper() == Looper.myLooper()) throw new IOException(ERROR_MAIN_THREAD);
throw new UnsupportedOperationException();
}
/**
* Returns a token that authorizes an Entity (example: cloud service) to perform
* an action on behalf of the application identified by Instance ID.
* <p/>
* This is similar to an OAuth2 token except, it applies to the
* application instance instead of a user.
* <p/>
* Do not call this function on the main thread.
*
* @param authorizedEntity Entity authorized by the token.
* @param scope Action authorized for authorizedEntity.
* @return a token that can identify and authorize the instance of the
* application on the device.
* @throws IOException if the request fails.
*/
public String getToken(String authorizedEntity, String scope) throws IOException {
return getToken(authorizedEntity, scope, null);
}
@PublicApi(exclude = true)
public InstanceIdStore getStore() {
return storeInstance;
}
@PublicApi(exclude = true)
public String requestToken(String authorizedEntity, String scope, Bundle extras) {
throw new UnsupportedOperationException();
}
private synchronized KeyPair getKeyPair() {
if (keyPair == null) {
keyPair = storeInstance.getKeyPair(subtype);
if (keyPair == null) {
try {
KeyPairGenerator rsaGenerator = KeyPairGenerator.getInstance("RSA");
rsaGenerator.initialize(RSA_KEY_SIZE);
keyPair = rsaGenerator.generateKeyPair();
creationTime = System.currentTimeMillis();
storeInstance.put(subtype, keyPair, creationTime);
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, e);
}
}
}
return keyPair;
}
@PublicApi(exclude = true)
public static String sha1KeyPair(KeyPair keyPair) {
try {
byte[] digest = MessageDigest.getInstance("SHA1").digest(keyPair.getPublic().getEncoded());
digest[0] = (byte) (112 + (0xF & digest[0]) & 0xFF);
return Base64.encodeToString(digest, 0, 8, Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING);
} catch (NoSuchAlgorithmException e) {
Log.w(TAG, e);
return null;
}
}
}

View file

@ -1,138 +0,0 @@
/*
* Copyright (C) 2013-2017 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 com.google.android.gms.iid;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Handler;
import android.os.IBinder;
import android.os.Looper;
import android.os.Message;
import android.support.v4.content.WakefulBroadcastReceiver;
import static org.microg.gms.gcm.GcmConstants.ACTION_C2DM_REGISTRATION;
import static org.microg.gms.gcm.GcmConstants.ACTION_INSTANCE_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_FROM;
import static org.microg.gms.gcm.GcmConstants.EXTRA_GSF_INTENT;
/**
* Base class to handle Instance ID service notifications on token
* refresh.
* <p/>
* Any app using Instance ID or GCM must include a class extending
* InstanceIDListenerService and implement {@link com.google.android.gms.iid.InstanceIDListenerService#onTokenRefresh()}.
* <p/>
* Include the following in the manifest:
* <pre>
* <service android:name=".YourInstanceIDListenerService" android:exported="false">
* <intent-filter>
* <action android:name="com.google.android.gms.iid.InstanceID"/>
* </intent-filter>
* </service></pre>
* Do not export this service. Instead, keep it private to prevent other apps
* accessing your service.
*/
public class InstanceIDListenerService extends Service {
private BroadcastReceiver registrationReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
handleIntent(intent);
stop();
}
};
private MessengerCompat messengerCompat = new MessengerCompat(new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
handleIntent((Intent) msg.obj);
}
});
private int counter = 0;
private int startId = -1;
private void handleIntent(Intent intent) {
// TODO
}
public IBinder onBind(Intent intent) {
if (intent != null && ACTION_INSTANCE_ID.equals(intent.getAction())) {
return messengerCompat.getBinder();
}
return null;
}
public void onCreate() {
IntentFilter filter = new IntentFilter(ACTION_C2DM_REGISTRATION);
filter.addCategory(getPackageName());
registerReceiver(registrationReceiver, filter);
}
public void onDestroy() {
unregisterReceiver(registrationReceiver);
}
public int onStartCommand(Intent intent, int flags, int startId) {
synchronized (this) {
this.counter++;
if (startId > this.startId) this.startId = startId;
}
try {
if (intent != null) {
if (ACTION_INSTANCE_ID.equals(intent.getAction()) && intent.hasExtra(EXTRA_GSF_INTENT)) {
startService((Intent) intent.getParcelableExtra(EXTRA_GSF_INTENT));
return START_STICKY;
}
handleIntent(intent);
if (intent.hasExtra(EXTRA_FROM))
WakefulBroadcastReceiver.completeWakefulIntent(intent);
}
} finally {
stop();
}
return START_NOT_STICKY;
}
/**
* Called when the system determines that the tokens need to be refreshed. The application
* should call getToken() and send the tokens to all application servers.
* <p/>
* This will not be called very frequently, it is needed for key rotation and to handle special
* cases.
* <p/>
* The system will throttle the refresh event across all devices to avoid overloading
* application servers with token updates.
*/
public void onTokenRefresh() {
// To be overwritten
}
private void stop() {
synchronized (this) {
counter--;
if (counter <= 0) {
stopSelf(startId);
}
}
}
}

View file

@ -1,423 +0,0 @@
/*
* Copyright (C) 2013-2017 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.iid;
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.Build;
import android.os.Bundle;
import android.os.ConditionVariable;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.os.Messenger;
import android.os.Parcelable;
import android.os.RemoteException;
import android.os.SystemClock;
import android.text.TextUtils;
import android.util.Base64;
import android.util.Log;
import com.google.android.gms.iid.InstanceID;
import com.google.android.gms.iid.MessengerCompat;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.util.HashMap;
import java.util.Map;
import java.util.Random;
import static android.content.pm.PackageManager.PERMISSION_GRANTED;
import static com.google.android.gms.iid.InstanceID.ERROR_BACKOFF;
import static com.google.android.gms.iid.InstanceID.ERROR_MISSING_INSTANCEID_SERVICE;
import static com.google.android.gms.iid.InstanceID.ERROR_SERVICE_NOT_AVAILABLE;
import static com.google.android.gms.iid.InstanceID.ERROR_TIMEOUT;
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.common.Constants.MAX_REFERENCE_VERSION;
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_INSTANCE_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP;
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP_VERSION_CODE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_APP_VERSION_NAME;
import static org.microg.gms.gcm.GcmConstants.EXTRA_CLIENT_VERSION;
import static org.microg.gms.gcm.GcmConstants.EXTRA_ERROR;
import static org.microg.gms.gcm.GcmConstants.EXTRA_GMS_VERSION;
import static org.microg.gms.gcm.GcmConstants.EXTRA_GSF_INTENT;
import static org.microg.gms.gcm.GcmConstants.EXTRA_IS_MESSENGER2;
import static org.microg.gms.gcm.GcmConstants.EXTRA_KID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_MESSENGER;
import static org.microg.gms.gcm.GcmConstants.EXTRA_OS_VERSION;
import static org.microg.gms.gcm.GcmConstants.EXTRA_PUBLIC_KEY;
import static org.microg.gms.gcm.GcmConstants.EXTRA_REGISTRATION_ID;
import static org.microg.gms.gcm.GcmConstants.EXTRA_SIGNATURE;
import static org.microg.gms.gcm.GcmConstants.EXTRA_UNREGISTERED;
import static org.microg.gms.gcm.GcmConstants.EXTRA_USE_GSF;
import static org.microg.gms.gcm.GcmConstants.PERMISSION_RECEIVE;
public class InstanceIdRpc {
private static final String TAG = "InstanceID/Rpc";
private static final int BLOCKING_WAIT_TIME = 30000;
private static String iidPackageName;
private static int lastRequestId;
private static int retryCount;
private static Map<String, Object> blockingResponses = new HashMap<String, Object>();
private long nextAttempt;
private int interval;
private Context context;
private PendingIntent selfAuthToken;
private Messenger messenger;
private Messenger myMessenger;
private MessengerCompat messengerCompat;
public InstanceIdRpc(Context context) {
this.context = context;
}
public static String getIidPackageName(Context context) {
if (iidPackageName != null) {
return iidPackageName;
}
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 iidPackageName = resolveInfo.serviceInfo.packageName;
}
}
try {
ApplicationInfo appInfo = packageManager.getApplicationInfo(GMS_PACKAGE_NAME, 0);
return iidPackageName = appInfo.packageName;
} catch (PackageManager.NameNotFoundException ignored) {
}
try {
ApplicationInfo appInfo = packageManager.getApplicationInfo(GSF_PACKAGE_NAME, 0);
return iidPackageName = appInfo.packageName;
} catch (PackageManager.NameNotFoundException ex3) {
Log.w(TAG, "Both Google Play Services and legacy GSF package are missing");
return null;
}
}
private static int getGmsVersionCode(final Context context) {
final PackageManager packageManager = context.getPackageManager();
try {
return packageManager.getPackageInfo(getIidPackageName(context), 0).versionCode;
} catch (PackageManager.NameNotFoundException ex) {
return -1;
}
}
private static int getSelfVersionCode(final Context context) {
try {
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionCode;
} catch (PackageManager.NameNotFoundException neverHappens) {
return 0;
}
}
private static String getSelfVersionName(final Context context) {
try {
return context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
} catch (PackageManager.NameNotFoundException neverHappens) {
return null;
}
}
void initialize() {
if (myMessenger != null) return;
getIidPackageName(context);
myMessenger = new Messenger(new Handler(Looper.getMainLooper()) {
@Override
public void handleMessage(Message msg) {
if (msg == null) {
return;
}
if (msg.obj instanceof Intent) {
Intent intent = (Intent) msg.obj;
intent.setExtrasClassLoader(MessengerCompat.class.getClassLoader());
if (intent.hasExtra(EXTRA_MESSENGER)) {
Parcelable messengerCandidate = intent.getParcelableExtra(EXTRA_MESSENGER);
if (messengerCandidate instanceof MessengerCompat) {
messengerCompat = (MessengerCompat) messengerCandidate;
} else if (messengerCandidate instanceof Messenger) {
messenger = (Messenger) messengerCandidate;
}
}
handleResponseInternal(intent);
} else {
Log.w(TAG, "Dropping invalid message");
}
}
});
}
public void handleResponseInternal(Intent resultIntent) {
if (resultIntent == null) return;
if (!ACTION_C2DM_REGISTRATION.equals(resultIntent.getAction()) && !ACTION_INSTANCE_ID.equals(resultIntent.getAction()))
return;
String result = resultIntent.getStringExtra(EXTRA_REGISTRATION_ID);
if (result == null) result = resultIntent.getStringExtra(EXTRA_UNREGISTERED);
if (result == null) {
handleError(resultIntent);
return;
}
retryCount = 0;
nextAttempt = 0;
interval = 0;
String requestId = null;
if (result.startsWith("|")) {
// parse structured response
String[] split = result.split("\\|");
if (!"ID".equals(split[1])) {
Log.w(TAG, "Unexpected structured response " + result);
}
requestId = split[2];
if (split.length > 4) {
if ("SYNC".equals(split[3])) {
// TODO: sync
} else if("RST".equals(split[3])) {
// TODO: rst
resultIntent.removeExtra(EXTRA_REGISTRATION_ID);
return;
}
}
result = split[split.length-1];
if (result.startsWith(":"))
result = result.substring(1);
resultIntent.putExtra(EXTRA_REGISTRATION_ID, result);
}
setResponse(requestId, resultIntent);
}
private void handleError(Intent resultIntent) {
String error = resultIntent.getStringExtra("error");
if (error == null) return;
String requestId = null;
if (error.startsWith("|")) {
// parse structured error message
String[] split = error.split("\\|");
if (!"ID".equals(split[1])) {
Log.w(TAG, "Unexpected structured response " + error);
}
if (split.length > 2) {
requestId = split[2];
error = split[3];
if (error.startsWith(":"))
error = error.substring(1);
} else {
error = "UNKNOWN";
}
resultIntent.putExtra("error", error);
}
setResponse(requestId, resultIntent);
long retryAfter = resultIntent.getLongExtra("Retry-After", 0);
if (retryAfter > 0) {
interval = (int) (retryAfter * 1000);
nextAttempt = SystemClock.elapsedRealtime() + interval;
Log.d(TAG, "Server requested retry delay: " + interval);
} else if (ERROR_SERVICE_NOT_AVAILABLE.equals(error) || "AUTHENTICATION_FAILED".equals(error)
&& GSF_PACKAGE_NAME.equals(getIidPackageName(context))) {
retryCount++;
if (retryCount < 3) return;
if (retryCount == 3) interval = 1000 + new Random().nextInt(1000);
interval = interval * 2;
nextAttempt = SystemClock.elapsedRealtime() + interval;
Log.d(TAG, "Setting retry delay to " + interval);
}
}
private synchronized PendingIntent getSelfAuthToken() {
if (selfAuthToken == null) {
Intent intent = new Intent();
intent.setPackage("com.google.example.invalidpackage");
selfAuthToken = PendingIntent.getBroadcast(context, 0, intent, 0);
}
return selfAuthToken;
}
private static synchronized String getRequestId() {
return Integer.toString(lastRequestId++);
}
private void sendRegisterMessage(Bundle data, KeyPair keyPair, String requestId) throws IOException {
long elapsedRealtime = SystemClock.elapsedRealtime();
if (nextAttempt != 0 && elapsedRealtime <= nextAttempt) {
Log.w(TAG, "Had to wait for " + interval + ", that's still " + (nextAttempt - elapsedRealtime));
throw new IOException(ERROR_BACKOFF);
}
initialize();
if (iidPackageName == null) {
throw new IOException(ERROR_MISSING_INSTANCEID_SERVICE);
}
Intent intent = new Intent(ACTION_C2DM_REGISTER);
intent.setPackage(iidPackageName);
data.putString(EXTRA_GMS_VERSION, Integer.toString(getGmsVersionCode(context)));
data.putString(EXTRA_OS_VERSION, Integer.toString(Build.VERSION.SDK_INT));
data.putString(EXTRA_APP_VERSION_CODE, Integer.toString(getSelfVersionCode(context)));
data.putString(EXTRA_APP_VERSION_NAME, getSelfVersionName(context));
data.putString(EXTRA_CLIENT_VERSION, "iid-" + MAX_REFERENCE_VERSION);
data.putString(EXTRA_APP_ID, InstanceID.sha1KeyPair(keyPair));
String pub = base64encode(keyPair.getPublic().getEncoded());
data.putString(EXTRA_PUBLIC_KEY, pub);
data.putString(EXTRA_SIGNATURE, sign(keyPair, context.getPackageName(), pub));
intent.putExtras(data);
intent.putExtra(EXTRA_APP, getSelfAuthToken());
sendRequest(intent, requestId);
}
private static String sign(KeyPair keyPair, String... payload) {
byte[] bytes;
try {
bytes = TextUtils.join("\n", payload).getBytes("UTF-8");
} catch (UnsupportedEncodingException e) {
Log.e(TAG, "Unable to encode", e);
return null;
}
PrivateKey privateKey = keyPair.getPrivate();
try {
Signature signature = Signature.getInstance(privateKey instanceof RSAPrivateKey ? "SHA256withRSA" : "SHA256withECDSA");
signature.initSign(privateKey);
signature.update(bytes);
return base64encode(signature.sign());
} catch (GeneralSecurityException e) {
Log.e(TAG, "Unable to sign", e);
return null;
}
}
private static String base64encode(byte[] bytes) {
return Base64.encodeToString(bytes, Base64.URL_SAFE + Base64.NO_PADDING + Base64.NO_WRAP);
}
private void sendRequest(Intent intent, String requestId) {
intent.putExtra(EXTRA_KID, "|ID|" + requestId + "|");
intent.putExtra("X-" + EXTRA_KID, "|ID|" + requestId + "|");
Log.d(TAG, "Sending " + intent.getExtras());
if (messenger != null) {
intent.putExtra(EXTRA_MESSENGER, myMessenger);
Message msg = Message.obtain();
msg.obj = intent;
try {
messenger.send(msg);
return;
} catch (RemoteException e) {
Log.d(TAG, "Messenger failed, falling back to service");
}
}
boolean useGsf = iidPackageName.endsWith(".gsf");
if (intent.hasExtra(EXTRA_USE_GSF))
useGsf = "1".equals(intent.getStringExtra(EXTRA_USE_GSF));
if (useGsf) {
Intent holder = new Intent(ACTION_INSTANCE_ID);
holder.setPackage(context.getPackageName());
holder.putExtra(EXTRA_GSF_INTENT, intent);
context.startService(holder);
} else {
intent.putExtra(EXTRA_MESSENGER, myMessenger);
intent.putExtra(EXTRA_IS_MESSENGER2, "1");
if (messengerCompat != null) {
Message msg = Message.obtain();
msg.obj = intent;
try {
messengerCompat.send(msg);
return;
} catch (RemoteException e) {
Log.d(TAG, "Messenger failed, falling back to service");
}
}
context.startService(intent);
}
}
public Intent sendRegisterMessageBlocking(Bundle data, KeyPair keyPair) throws IOException {
Intent intent = sendRegisterMessageBlockingInternal(data, keyPair);
if (intent != null && intent.hasExtra(EXTRA_MESSENGER)) {
// Now with a messenger
intent = sendRegisterMessageBlockingInternal(data, keyPair);
}
return intent;
}
private Intent sendRegisterMessageBlockingInternal(Bundle data, KeyPair keyPair) throws IOException {
ConditionVariable cv = new ConditionVariable();
String requestId = getRequestId();
synchronized (InstanceIdRpc.class) {
blockingResponses.put(requestId, cv);
}
sendRegisterMessage(data, keyPair, requestId);
cv.block(BLOCKING_WAIT_TIME);
synchronized (InstanceIdRpc.class) {
Object res = blockingResponses.remove(requestId);
if (res instanceof Intent) {
return (Intent) res;
} else if (res instanceof String) {
throw new IOException((String) res);
}
Log.w(TAG, "No response " + res);
throw new IOException(ERROR_TIMEOUT);
}
}
public String handleRegisterMessageResult(Intent resultIntent) throws IOException {
if (resultIntent == null) throw new IOException(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 : ERROR_SERVICE_NOT_AVAILABLE);
}
private void setResponse(String requestId, Object response) {
if (requestId == null) {
for (String r : blockingResponses.keySet()) {
setResponse(r, response);
}
}
Object old = blockingResponses.get(requestId);
blockingResponses.put(requestId, response);
if (old instanceof ConditionVariable) {
((ConditionVariable) old).open();
} else if (old instanceof Messenger) {
Message msg = Message.obtain();
msg.obj = response;
try {
((Messenger) old).send(msg);
} catch (RemoteException e) {
Log.w(TAG, "Failed to send response", e);
}
}
}
}

View file

@ -1,111 +0,0 @@
/*
* Copyright (C) 2013-2017 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.iid;
import android.content.Context;
import android.content.SharedPreferences;
import android.util.Base64;
import android.util.Log;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
public class InstanceIdStore {
private static final String TAG = "InstanceID/Store";
private static final String PREF_NAME = "com.google.android.gms.appid";
private Context context;
private SharedPreferences sharedPreferences;
public InstanceIdStore(Context context) {
this.context = context;
this.sharedPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);
}
public synchronized String get(String key) {
return sharedPreferences.getString(key, null);
}
public String get(String subtype, String key) {
return get(subtype + "|S|" + key);
}
public String get(String subtype, String authorizedEntity, String scope) {
return get(subtype + "|T|" + authorizedEntity + "|" + scope);
}
public KeyPair getKeyPair(String subtype) {
String pub = get(subtype, "|P|");
String priv = get(subtype, "|K|");
if (pub == null || priv == null) {
return null;
}
try {
byte[] pubKey = Base64.decode(pub, Base64.URL_SAFE);
byte[] privKey = Base64.decode(priv, Base64.URL_SAFE);
KeyFactory rsaFactory = KeyFactory.getInstance("RSA");
return new KeyPair(rsaFactory.generatePublic(new X509EncodedKeySpec(pubKey)), rsaFactory.generatePrivate(new PKCS8EncodedKeySpec(privKey)));
} catch (Exception e) {
Log.w(TAG, "Invalid key stored " + e);
return null;
}
}
public synchronized void put(String key, String value) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.putString(key, value);
editor.apply();
}
public void put(String subtype, String key, String value) {
put(subtype + "|S|" + key, value);
}
public void put(String subtype, String authorizedEntity, String scope, String value) {
put(subtype + "|T|" + authorizedEntity + "|" + scope, value);
}
public synchronized void put(String subtype, KeyPair keyPair, long timestamp) {
put(subtype, "|P|", Base64.encodeToString(keyPair.getPublic().getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING));
put(subtype, "|K|", Base64.encodeToString(keyPair.getPrivate().getEncoded(), Base64.URL_SAFE | Base64.NO_WRAP | Base64.NO_PADDING));
put(subtype, "cre", Long.toString(timestamp));
}
public synchronized void delete() {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.clear();
editor.apply();
}
public synchronized void delete(String prefix) {
SharedPreferences.Editor editor = sharedPreferences.edit();
for (String key : sharedPreferences.getAll().keySet()) {
if (key.startsWith(prefix)) {
editor.remove(key);
}
}
editor.apply();
}
public synchronized void delete(String subtype, String authorizedEntity, String scope) {
SharedPreferences.Editor editor = sharedPreferences.edit();
editor.remove(subtype + "|T|" + authorizedEntity + "|" + scope);
editor.apply();
}
}

View file

@ -1,54 +0,0 @@
/*
* Copyright 2013-2015 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.
*/
apply plugin: 'com.android.library'
String getMyVersionName() {
def stdout = new ByteArrayOutputStream()
if (rootProject.file("gradlew").exists())
exec { commandLine 'git', 'describe', '--tags', '--always', '--dirty'; standardOutput = stdout }
else // automatic build system, don't tag dirty
exec { commandLine 'git', 'describe', '--tags', '--always'; standardOutput = stdout }
return stdout.toString().trim().substring(1)
}
android {
compileSdkVersion androidCompileSdk()
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName getMyVersionName()
minSdkVersion androidMinSdk()
targetSdkVersion androidTargetSdk()
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
lintOptions {
disable 'InvalidPackage'
}
}
dependencies {
api project(':play-services-base')
api project(':play-services-cast')
api project(':play-services-gcm')
api project(':play-services-location')
api project(':play-services-wearable')
}

View file

@ -1,34 +0,0 @@
#
# 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.
#
POM_NAME=Play Services Library
POM_DESCRIPTION=The whole package of Play Services libraries. Use play-services-* artifacts if you only need certain parts
POM_PACKAGING=aar
POM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_URL=https://github.com/microg/android_external_GmsLib
POM_SCM_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_SCM_DEV_CONNECTION=scm:git@github.com:microg/android_external_GmsLib.git
POM_LICENCE_NAME=The Apache Software License, Version 2.0
POM_LICENCE_URL=http://www.apache.org/licenses/LICENSE-2.0.txt
POM_LICENCE_DIST=repo
POM_DEVELOPER_ID=mar-v-in
POM_DEVELOPER_NAME=Marvin W

View file

@ -1,22 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2013-2017 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.
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="org.microg.gms">
<application />
</manifest>