Repo Created

This commit is contained in:
Fr4nz D13trich 2025-11-15 17:44:12 +01:00
parent eb305e2886
commit a8c22c65db
4784 changed files with 329907 additions and 2 deletions

View file

@ -0,0 +1,49 @@
/*
* SPDX-FileCopyrightText: 2015 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
apply plugin: 'com.android.library'
apply plugin: 'maven-publish'
apply plugin: 'signing'
android {
namespace "com.google.android.gms.cast"
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
aidlPackagedList "com/google/android/gms/cast/ApplicationMetadata.aidl"
aidlPackagedList "com/google/android/gms/cast/LaunchOptions.aidl"
buildFeatures {
aidl = true
}
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
}
apply from: '../gradle/publish-android.gradle'
description = 'microG implementation of play-services-cast'
dependencies {
// Dependencies from play-services-cast:21.2.0
api "androidx.core:core:1.0.0"
api "androidx.mediarouter:mediarouter:1.2.2"
api project(':play-services-base')
api project(':play-services-basement')
//api project(':play-services-flags')
api project(':play-services-tasks')
annotationProcessor project(':safe-parcel-processor')
}

View file

@ -0,0 +1,61 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
apply plugin: 'com.android.library'
apply plugin: 'kotlin-android'
apply plugin: 'maven-publish'
apply plugin: 'signing'
dependencies {
implementation project(':play-services-cast')
implementation project(':play-services-base-core')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlinVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutineVersion"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutineVersion"
// TODO: Switch to upstream once raw requests are merged
// https://github.com/vitalidze/chromecast-java-api-v2/pull/99
// implementation "su.litvak.chromecast:api-v2:0.10.4"
implementation "info.armills.chromecast-java-api-v2:api-v2-raw-request:0.10.4-raw-request-1"
}
android {
namespace "org.microg.gms.cast.core"
compileSdkVersion androidCompileSdk
buildToolsVersion "$androidBuildVersionTools"
defaultConfig {
versionName version
minSdkVersion androidMinSdk
targetSdkVersion androidTargetSdk
}
buildFeatures {
dataBinding = true
}
sourceSets {
main.java.srcDirs += 'src/main/kotlin'
}
lintOptions {
disable 'MissingTranslation'
}
compileOptions {
sourceCompatibility = 1.8
targetCompatibility = 1.8
}
kotlinOptions {
jvmTarget = 1.8
}
}
apply from: '../../gradle/publish-android.gradle'
description = 'microG service implementation for play-services-cast'

View file

@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ SPDX-FileCopyrightText: 2022 microG Project Team
~ SPDX-License-Identifier: Apache-2.0
-->
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
<application>
<service android:name="com.google.android.gms.cast.media.CastMediaRouteProviderService">
<intent-filter>
<action android:name="android.media.MediaRouteProviderService" />
</intent-filter>
</service>
<service android:name="org.microg.gms.cast.CastDeviceControllerService">
<intent-filter>
<action android:name="com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE" />
</intent-filter>
</service>
</application>
</manifest>

View file

@ -0,0 +1,33 @@
/*
* 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.media;
import org.microg.gms.cast.CastMediaRouteProvider;
import android.util.Log;
import androidx.mediarouter.media.MediaRouteProvider;
import androidx.mediarouter.media.MediaRouteProviderService;
public class CastMediaRouteProviderService extends MediaRouteProviderService {
private static final String TAG = CastMediaRouteProviderService.class.getSimpleName();
@Override
public MediaRouteProvider onCreateMediaRouteProvider() {
return new CastMediaRouteProvider(this);
}
}

View file

@ -0,0 +1,328 @@
/*
* 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 java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import android.content.Context;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcel;
import android.os.RemoteException;
import android.util.Base64;
import android.util.Log;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.gms.cast.ApplicationStatus;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.CastDeviceStatus;
import com.google.android.gms.cast.JoinOptions;
import com.google.android.gms.cast.LaunchOptions;
import com.google.android.gms.cast.internal.ICastDeviceController;
import com.google.android.gms.cast.internal.ICastDeviceControllerListener;
import com.google.android.gms.common.api.CommonStatusCodes;
import com.google.android.gms.common.api.Status;
import com.google.android.gms.common.images.WebImage;
import com.google.android.gms.common.internal.BinderWrapper;
import com.google.android.gms.common.internal.GetServiceRequest;
import su.litvak.chromecast.api.v2.Application;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.Namespace;
import su.litvak.chromecast.api.v2.ChromeCastConnectionEventListener;
import su.litvak.chromecast.api.v2.ChromeCastSpontaneousEventListener;
import su.litvak.chromecast.api.v2.ChromeCastRawMessageListener;
import su.litvak.chromecast.api.v2.ChromeCastConnectionEvent;
import su.litvak.chromecast.api.v2.ChromeCastSpontaneousEvent;
import su.litvak.chromecast.api.v2.ChromeCastRawMessage;
import su.litvak.chromecast.api.v2.AppEvent;
public class CastDeviceControllerImpl extends ICastDeviceController.Stub implements
ChromeCastConnectionEventListener,
ChromeCastSpontaneousEventListener,
ChromeCastRawMessageListener,
ICastDeviceControllerListener
{
private static final String TAG = "GmsCastDeviceController";
private Context context;
private String packageName;
private CastDevice castDevice;
boolean notificationEnabled;
long castFlags;
ICastDeviceControllerListener listener;
ChromeCast chromecast;
String sessionId = null;
public CastDeviceControllerImpl(Context context, String packageName, Bundle extras) {
this.context = context;
this.packageName = packageName;
extras.setClassLoader(BinderWrapper.class.getClassLoader());
this.castDevice = CastDevice.getFromBundle(extras);
this.notificationEnabled = extras.getBoolean("com.google.android.gms.cast.EXTRA_CAST_FRAMEWORK_NOTIFICATION_ENABLED");
this.castFlags = extras.getLong("com.google.android.gms.cast.EXTRA_CAST_FLAGS");
BinderWrapper listenerWrapper = (BinderWrapper)extras.get("listener");
if (listenerWrapper != null) {
this.listener = ICastDeviceControllerListener.Stub.asInterface(listenerWrapper.binder);
}
this.chromecast = new ChromeCast(this.castDevice.getAddress());
this.chromecast.registerListener(this);
this.chromecast.registerRawMessageListener(this);
this.chromecast.registerConnectionListener(this);
}
@Override
public void connectionEventReceived(ChromeCastConnectionEvent event) {
if (!event.isConnected()) {
this.onDisconnected(CommonStatusCodes.SUCCESS);
}
}
protected ApplicationMetadata createMetadataFromApplication(Application app) {
if (app == null) {
return null;
}
ApplicationMetadata metadata = new ApplicationMetadata();
metadata.applicationId = app.id;
metadata.name = app.name;
Log.d(TAG, "unimplemented: ApplicationMetadata.images");
Log.d(TAG, "unimplemented: ApplicationMetadata.senderAppLaunchUri");
metadata.images = new ArrayList<WebImage>();
metadata.namespaces = new ArrayList<String>();
for(Namespace namespace : app.namespaces) {
metadata.namespaces.add(namespace.name);
}
metadata.senderAppIdentifier = this.context.getPackageName();
return metadata;
}
@Override
public void spontaneousEventReceived(ChromeCastSpontaneousEvent event) {
switch (event.getType()) {
case MEDIA_STATUS:
break;
case STATUS:
su.litvak.chromecast.api.v2.Status status = (su.litvak.chromecast.api.v2.Status)event.getData();
Application app = status.getRunningApp();
ApplicationMetadata metadata = this.createMetadataFromApplication(app);
if (app != null) {
this.onApplicationStatusChanged(new ApplicationStatus(app.statusText));
}
int activeInputState = status.activeInput ? 1 : 0;
int standbyState = status.standBy ? 1 : 0;
this.onDeviceStatusChanged(new CastDeviceStatus(status.volume.level, status.volume.muted, activeInputState, metadata, standbyState));
break;
case APPEVENT:
break;
case CLOSE:
this.onApplicationDisconnected(CommonStatusCodes.SUCCESS);
break;
default:
break;
}
}
@Override
public void rawMessageReceived(ChromeCastRawMessage message, Long requestId) {
switch (message.getPayloadType()) {
case STRING:
String response = message.getPayloadUtf8();
if (requestId == null) {
this.onTextMessageReceived(message.getNamespace(), response);
} else {
this.onSendMessageSuccess(response, requestId);
this.onTextMessageReceived(message.getNamespace(), response);
}
break;
case BINARY:
byte[] payload = message.getPayloadBinary();
this.onBinaryMessageReceived(message.getNamespace(), payload);
break;
}
}
@Override
public void disconnect() {
try {
this.chromecast.disconnect();
} catch (IOException e) {
Log.e(TAG, "Error disconnecting chromecast: " + e.getMessage());
return;
}
}
@Override
public void sendMessage(String namespace, String message, long requestId) {
try {
this.chromecast.sendRawRequest(namespace, message, requestId);
} catch (IOException e) {
Log.w(TAG, "Error sending cast message: " + e.getMessage());
this.onSendMessageFailure("", requestId, CommonStatusCodes.NETWORK_ERROR);
return;
}
}
@Override
public void stopApplication(String sessionId) {
try {
this.chromecast.stopSession(sessionId);
} catch (IOException e) {
Log.w(TAG, "Error sending cast message: " + e.getMessage());
return;
}
this.sessionId = null;
}
@Override
public void registerNamespace(String namespace) {
Log.d(TAG, "unimplemented Method: registerNamespace");
}
@Override
public void unregisterNamespace(String namespace) {
Log.d(TAG, "unimplemented Method: unregisterNamespace");
}
@Override
public void launchApplication(String applicationId, LaunchOptions launchOptions) {
Application app = null;
try {
app = this.chromecast.launchApp(applicationId);
} catch (IOException e) {
Log.w(TAG, "Error launching cast application: " + e.getMessage());
this.onApplicationConnectionFailure(CommonStatusCodes.NETWORK_ERROR);
return;
}
this.sessionId = app.sessionId;
ApplicationMetadata metadata = this.createMetadataFromApplication(app);
this.onApplicationConnectionSuccess(metadata, app.statusText, app.sessionId, true);
}
@Override
public void joinApplication(String applicationId, String sessionId, JoinOptions joinOptions) {
Log.d(TAG, "unimplemented Method: joinApplication");
this.launchApplication(applicationId, new LaunchOptions());
}
public void onDisconnected(int reason) {
if (this.listener != null) {
try {
this.listener.onDisconnected(reason);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onDisconnected: " + ex.getMessage());
}
}
}
public void onApplicationConnectionSuccess(ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) {
if (this.listener != null) {
try {
this.listener.onApplicationConnectionSuccess(applicationMetadata, applicationStatus, sessionId, wasLaunched);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onApplicationConnectionSuccess: " + ex.getMessage());
}
}
}
public void onApplicationConnectionFailure(int statusCode) {
if (this.listener != null) {
try {
this.listener.onApplicationConnectionFailure(statusCode);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onApplicationConnectionFailure: " + ex.getMessage());
}
}
}
public void onTextMessageReceived(String namespace, String message) {
if (this.listener != null) {
try {
this.listener.onTextMessageReceived(namespace, message);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onTextMessageReceived: " + ex.getMessage());
}
}
}
public void onBinaryMessageReceived(String namespace, byte[] data) {
if (this.listener != null) {
try {
this.listener.onBinaryMessageReceived(namespace, data);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onBinaryMessageReceived: " + ex.getMessage());
}
}
}
public void onApplicationDisconnected(int paramInt) {
Log.d(TAG, "unimplemented Method: onApplicationDisconnected");
if (this.listener != null) {
try {
this.listener.onApplicationDisconnected(paramInt);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onApplicationDisconnected: " + ex.getMessage());
}
}
}
public void onSendMessageFailure(String response, long requestId, int statusCode) {
if (this.listener != null) {
try {
this.listener.onSendMessageFailure(response, requestId, statusCode);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onSendMessageFailure: " + ex.getMessage());
}
}
}
public void onSendMessageSuccess(String response, long requestId) {
if (this.listener != null) {
try {
this.listener.onSendMessageSuccess(response, requestId);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onSendMessageSuccess: " + ex.getMessage());
}
}
}
public void onApplicationStatusChanged(ApplicationStatus applicationStatus) {
if (this.listener != null) {
try {
this.listener.onApplicationStatusChanged(applicationStatus);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onApplicationStatusChanged: " + ex.getMessage());
}
}
}
public void onDeviceStatusChanged(CastDeviceStatus deviceStatus) {
if (this.listener != null) {
try {
this.listener.onDeviceStatusChanged(deviceStatus);
} catch (RemoteException ex) {
Log.e(TAG, "Error calling onDeviceStatusChanged: " + ex.getMessage());
}
}
}
}

View file

@ -0,0 +1,50 @@
/*
* 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.os.IBinder;
import android.os.RemoteException;
import android.os.Parcel;
import android.util.ArrayMap;
import android.util.Log;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.internal.ICastDeviceControllerListener;
import com.google.android.gms.common.internal.GetServiceRequest;
import com.google.android.gms.common.internal.BinderWrapper;
import com.google.android.gms.common.internal.IGmsCallbacks;
import org.microg.gms.BaseService;
import org.microg.gms.common.GmsService;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.ChromeCasts;
import su.litvak.chromecast.api.v2.Status;
import su.litvak.chromecast.api.v2.ChromeCastsListener;
public class CastDeviceControllerService extends BaseService {
private static final String TAG = CastDeviceControllerService.class.getSimpleName();
public CastDeviceControllerService() {
super("GmsCastDeviceControllerSvc", GmsService.CAST);
}
@Override
public void handleServiceRequest(IGmsCallbacks callback, GetServiceRequest request, GmsService service) throws RemoteException {
callback.onPostInitComplete(0, new CastDeviceControllerImpl(this, request.packageName, request.extras), null);
}
}

View file

@ -0,0 +1,93 @@
/*
* 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.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import androidx.mediarouter.media.MediaRouteProvider;
import androidx.mediarouter.media.MediaRouter;
import com.google.android.gms.common.images.WebImage;
import com.google.android.gms.cast.CastDevice;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.io.IOException;
import java.lang.Thread;
import java.lang.Runnable;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
import su.litvak.chromecast.api.v2.ChromeCast;
import su.litvak.chromecast.api.v2.ChromeCasts;
import su.litvak.chromecast.api.v2.Status;
import su.litvak.chromecast.api.v2.ChromeCastsListener;
public class CastMediaRouteController extends MediaRouteProvider.RouteController {
private static final String TAG = CastMediaRouteController.class.getSimpleName();
private CastMediaRouteProvider provider;
private String routeId;
private ChromeCast chromecast;
public CastMediaRouteController(CastMediaRouteProvider provider, String routeId, String address) {
super();
this.provider = provider;
this.routeId = routeId;
this.chromecast = new ChromeCast(address);
}
public boolean onControlRequest(Intent intent, MediaRouter.ControlRequestCallback callback) {
Log.d(TAG, "unimplemented Method: onControlRequest: " + this.routeId);
return false;
}
public void onRelease() {
Log.d(TAG, "unimplemented Method: onRelease: " + this.routeId);
}
public void onSelect() {
Log.d(TAG, "unimplemented Method: onSelect: " + this.routeId);
}
public void onSetVolume(int volume) {
Log.d(TAG, "unimplemented Method: onSetVolume: " + this.routeId);
}
public void onUnselect() {
Log.d(TAG, "unimplemented Method: onUnselect: " + this.routeId);
}
public void onUnselect(int reason) {
Log.d(TAG, "unimplemented Method: onUnselect: " + this.routeId);
}
public void onUpdateVolume(int delta) {
Log.d(TAG, "unimplemented Method: onUpdateVolume: " + this.routeId);
}
}

View file

@ -0,0 +1,359 @@
/*
* 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.annotation.SuppressLint;
import android.content.Context;
import android.content.IntentFilter;
import android.net.Uri;
import android.net.nsd.NsdManager;
import android.net.nsd.NsdServiceInfo;
import android.os.Bundle;
import android.os.AsyncTask;
import android.os.Handler;
import android.util.Log;
import androidx.mediarouter.media.MediaControlIntent;
import androidx.mediarouter.media.MediaRouteDescriptor;
import androidx.mediarouter.media.MediaRouteDiscoveryRequest;
import androidx.mediarouter.media.MediaRouteProvider;
import androidx.mediarouter.media.MediaRouteProviderDescriptor;
import androidx.mediarouter.media.MediaRouter;
import com.google.android.gms.common.images.WebImage;
import com.google.android.gms.cast.CastDevice;
import com.google.android.gms.cast.CastMediaControlIntent;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Inet4Address;
import java.net.UnknownHostException;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.Thread;
import java.lang.Runnable;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.util.HashMap;
public class CastMediaRouteProvider extends MediaRouteProvider {
private static final String TAG = CastMediaRouteProvider.class.getSimpleName();
private Map<String, CastDevice> castDevices = new HashMap<String, CastDevice>();
private Map<String, String> serviceCastIds = new HashMap<String, String>();
private NsdManager mNsdManager;
private NsdManager.DiscoveryListener mDiscoveryListener;
private List<String> customCategories = new ArrayList<String>();
private enum State {
NOT_DISCOVERING,
DISCOVERY_REQUESTED,
DISCOVERING,
DISCOVERY_STOP_REQUESTED,
}
private State state = State.NOT_DISCOVERING;
private static final ArrayList<IntentFilter> BASE_CONTROL_FILTERS = new ArrayList<IntentFilter>();
static {
IntentFilter filter;
filter = new IntentFilter();
filter.addCategory(CastMediaControlIntent.CATEGORY_CAST);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_PLAY);
filter.addDataScheme("http");
filter.addDataScheme("https");
String[] types = {
"image/jpeg",
"image/pjpeg",
"image/jpg",
"image/webp",
"image/png",
"image/gif",
"image/bmp",
"image/vnd.microsoft.icon",
"image/x-icon",
"image/x-xbitmap",
"audio/wav",
"audio/x-wav",
"audio/mp3",
"audio/x-mp3",
"audio/x-m4a",
"audio/mpeg",
"audio/webm",
"audio/ogg",
"audio/x-matroska",
"video/mp4",
"video/x-m4v",
"video/mp2t",
"video/webm",
"video/ogg",
"video/x-matroska",
"application/x-mpegurl",
"application/vnd.apple.mpegurl",
"application/dash+xml",
"application/vnd.ms-sstr+xml",
};
for (String type : types) {
try {
filter.addDataType(type);
} catch (IntentFilter.MalformedMimeTypeException ex) {
Log.e(TAG, "Error adding filter type " + type);
}
}
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_PAUSE);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_RESUME);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_STOP);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_SEEK);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_GET_STATUS);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_START_SESSION);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_GET_SESSION_STATUS);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK);
filter.addAction(MediaControlIntent.ACTION_END_SESSION);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(CastMediaControlIntent.CATEGORY_CAST_REMOTE_PLAYBACK);
filter.addAction(CastMediaControlIntent.ACTION_SYNC_STATUS);
BASE_CONTROL_FILTERS.add(filter);
filter = new IntentFilter();
filter.addCategory(CastMediaControlIntent.CATEGORY_CAST_REMOTE_PLAYBACK);
filter.addAction(CastMediaControlIntent.ACTION_SYNC_STATUS);
BASE_CONTROL_FILTERS.add(filter);
}
@SuppressLint("NewApi")
public CastMediaRouteProvider(Context context) {
super(context);
if (android.os.Build.VERSION.SDK_INT < 16) {
Log.i(TAG, "Cast discovery disabled. Android SDK version 16 or higher required.");
return;
}
mNsdManager = (NsdManager)context.getApplicationContext().getSystemService(Context.NSD_SERVICE);
mDiscoveryListener = new NsdManager.DiscoveryListener() {
@Override
public void onDiscoveryStarted(String regType) {
CastMediaRouteProvider.this.state = State.DISCOVERING;
}
@Override
public void onServiceFound(NsdServiceInfo service) {
mNsdManager.resolveService(service, new NsdManager.ResolveListener() {
@Override
public void onResolveFailed(NsdServiceInfo serviceInfo, int errorCode) {
if (errorCode == NsdManager.FAILURE_ALREADY_ACTIVE) {
return;
}
Log.e(TAG, "DiscoveryListener Resolve failed. Error code " + errorCode);
}
@Override
public void onServiceResolved(NsdServiceInfo serviceInfo) {
String name = serviceInfo.getServiceName();
InetAddress host = serviceInfo.getHost();
int port = serviceInfo.getPort();
Map<String, byte[]> attributes = serviceInfo.getAttributes();
if (attributes == null) {
Log.e(TAG, "Error getting service attributes from DNS-SD response");
return;
}
try {
String id = new String(attributes.get("id"), "UTF-8");
String deviceVersion = new String(attributes.get("ve"), "UTF-8");
String friendlyName = new String(attributes.get("fn"), "UTF-8");
String modelName = new String(attributes.get("md"), "UTF-8");
String iconPath = new String(attributes.get("ic"), "UTF-8");
int status = Integer.parseInt(new String(attributes.get("st"), "UTF-8"));
onChromeCastDiscovered(id, name, host, port, deviceVersion, friendlyName, modelName, iconPath, status);
} catch (UnsupportedEncodingException | NullPointerException ex) {
Log.e(TAG, "Error getting cast details from DNS-SD response", ex);
return;
}
}
});
}
@Override
public void onServiceLost(NsdServiceInfo serviceInfo) {
String name = serviceInfo.getServiceName();
onChromeCastLost(name);
}
@Override
public void onDiscoveryStopped(String serviceType) {
CastMediaRouteProvider.this.state = State.NOT_DISCOVERING;
}
@Override
public void onStartDiscoveryFailed(String serviceType, int errorCode) {
CastMediaRouteProvider.this.state = State.NOT_DISCOVERING;
}
@Override
public void onStopDiscoveryFailed(String serviceType, int errorCode) {
CastMediaRouteProvider.this.state = State.DISCOVERING;
}
};
}
private void onChromeCastDiscovered(
String id, String name, InetAddress host, int port, String
deviceVersion, String friendlyName, String modelName, String
iconPath, int status) {
if (!this.castDevices.containsKey(id)) {
// TODO: Capabilities
int capabilities = CastDevice.CAPABILITY_VIDEO_OUT | CastDevice.CAPABILITY_AUDIO_OUT;
CastDevice castDevice = new CastDevice(id, name, host, port, deviceVersion, friendlyName, modelName, iconPath, status, capabilities);
this.castDevices.put(id, castDevice);
this.serviceCastIds.put(name, id);
}
publishRoutesInMainThread();
}
private void onChromeCastLost(String name) {
String id = this.serviceCastIds.remove(name);
if (id != null) {
this.castDevices.remove(id);
}
publishRoutesInMainThread();
}
@SuppressLint("NewApi")
@Override
public void onDiscoveryRequestChanged(MediaRouteDiscoveryRequest request) {
if (android.os.Build.VERSION.SDK_INT < 16) {
return;
}
if (request != null && request.isValid() && request.isActiveScan()) {
if (request.getSelector() != null) {
for (String category : request.getSelector().getControlCategories()) {
if (CastMediaControlIntent.isCategoryForCast(category)) {
this.customCategories.add(category);
}
}
}
if (this.state == State.NOT_DISCOVERING) {
mNsdManager.discoverServices("_googlecast._tcp.", NsdManager.PROTOCOL_DNS_SD, mDiscoveryListener);
this.state = State.DISCOVERY_REQUESTED;
}
} else {
if (this.state == State.DISCOVERING) {
mNsdManager.stopServiceDiscovery(mDiscoveryListener);
this.state = State.DISCOVERY_STOP_REQUESTED;
}
}
}
@Override
public RouteController onCreateRouteController(String routeId) {
CastDevice castDevice = this.castDevices.get(routeId);
if (castDevice == null) {
return null;
}
return new CastMediaRouteController(this, routeId, castDevice.getAddress());
}
private void publishRoutesInMainThread() {
Handler mainHandler = new Handler(this.getContext().getMainLooper());
mainHandler.post(new Runnable() {
@Override
public void run() {
publishRoutes();
}
});
}
private void publishRoutes() {
MediaRouteProviderDescriptor.Builder builder = new MediaRouteProviderDescriptor.Builder();
for (CastDevice castDevice : this.castDevices.values()) {
ArrayList<IntentFilter> controlFilters = new ArrayList<IntentFilter>(BASE_CONTROL_FILTERS);
// Include any app-specific control filters that have been requested.
// TODO: Do we need to check with the device?
for (String category : this.customCategories) {
IntentFilter filter = new IntentFilter();
filter.addCategory(category);
controlFilters.add(filter);
}
Bundle extras = new Bundle();
castDevice.putInBundle(extras);
MediaRouteDescriptor route = new MediaRouteDescriptor.Builder(
castDevice.getDeviceId(),
castDevice.getFriendlyName())
.setDescription(castDevice.getModelName())
.addControlFilters(controlFilters)
.setDeviceType(MediaRouter.RouteInfo.DEVICE_TYPE_TV)
.setPlaybackType(MediaRouter.RouteInfo.PLAYBACK_TYPE_REMOTE)
.setVolumeHandling(MediaRouter.RouteInfo.PLAYBACK_VOLUME_FIXED)
.setVolumeMax(20)
.setVolume(0)
.setEnabled(true)
.setExtras(extras)
.setConnectionState(MediaRouter.RouteInfo.CONNECTION_STATE_DISCONNECTED)
.build();
builder.addRoute(route);
}
this.setDescriptor(builder.build());
}
}

View file

@ -0,0 +1,18 @@
<?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 />

View file

@ -0,0 +1,3 @@
package com.google.android.gms.cast;
parcelable ApplicationMetadata;

View file

@ -0,0 +1,3 @@
package com.google.android.gms.cast;
parcelable ApplicationStatus;

View file

@ -0,0 +1,3 @@
package com.google.android.gms.cast;
parcelable CastDeviceStatus;

View file

@ -0,0 +1,3 @@
package com.google.android.gms.cast;
parcelable JoinOptions;

View file

@ -0,0 +1,3 @@
package com.google.android.gms.cast;
parcelable LaunchOptions;

View file

@ -0,0 +1,8 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.cast;
parcelable RequestItem;

View file

@ -0,0 +1,10 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.cast.internal;
interface IBundleCallback {
oneway void onBundle(in Bundle bundle);
}

View file

@ -0,0 +1,14 @@
package com.google.android.gms.cast.internal;
import com.google.android.gms.cast.LaunchOptions;
import com.google.android.gms.cast.JoinOptions;
interface ICastDeviceController {
oneway void disconnect() = 0;
oneway void stopApplication(String sessionId) = 4;
oneway void sendMessage(String namespace, String message, long requestId) = 8;
oneway void registerNamespace(String namespace) = 10;
oneway void unregisterNamespace(String namespace) = 11;
oneway void launchApplication(String applicationId, in LaunchOptions launchOptions) = 12;
oneway void joinApplication(String applicationId, String sessionId, in JoinOptions joinOptions) = 13;
}

View file

@ -0,0 +1,21 @@
package com.google.android.gms.cast.internal;
import com.google.android.gms.cast.ApplicationMetadata;
import com.google.android.gms.cast.ApplicationStatus;
import com.google.android.gms.cast.CastDeviceStatus;
interface ICastDeviceControllerListener {
void onDisconnected(int reason) = 0;
void onApplicationConnectionSuccess(in ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) = 1;
void onApplicationConnectionFailure(int statusCode) = 2;
// Deprecated: void onStatusReceived(String string1, double double1, boolean boolean1) = 3;
void onTextMessageReceived(String namespace, String message) = 4;
void onBinaryMessageReceived(String namespace, in byte[] data) = 5;
// void onStatusChanged(int status) = 6; // TODO
// void onStatusChanged2(int status) = 7; // TODO
void onApplicationDisconnected(int paramInt) = 8;
void onSendMessageFailure(String response, long requestId, int statusCode) = 9;
void onSendMessageSuccess(String response, long requestId) = 10;
void onApplicationStatusChanged(in ApplicationStatus applicationStatus) = 11;
void onDeviceStatusChanged(in CastDeviceStatus deviceStatus) = 12;
}

View file

@ -0,0 +1,18 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.cast.internal;
import com.google.android.gms.common.api.internal.IStatusCallback;
import com.google.android.gms.cast.internal.IBundleCallback;
import com.google.android.gms.cast.RequestItem;
interface ICastService {
oneway void broadcastPrecacheMessageLegacy(IStatusCallback callback, in String[] arg2, String precacheData) = 0;
oneway void broadcastPrecacheMessage(IStatusCallback callback, in String[] arg2, String precacheData, in List<RequestItem> requestItems) = 1;
oneway void getCxLessStatus(IStatusCallback callback) = 3;
oneway void getFeatureFlags(IBundleCallback callback, in String[] flags) = 4;
oneway void getCastStatusCodeDictionary(IBundleCallback callback, in String[] dictionaries) = 5;
}

View file

@ -0,0 +1,85 @@
/*
* 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.net.Uri;
import com.google.android.gms.common.images.WebImage;
import org.microg.gms.common.PublicApi;
import org.microg.safeparcel.AutoSafeParcelable;
import org.microg.safeparcel.SafeParceled;
import java.util.List;
@PublicApi
public class ApplicationMetadata extends AutoSafeParcelable {
@SafeParceled(1)
private int versionCode = 1;
@SafeParceled(2)
public String applicationId;
@SafeParceled(3)
public String name;
@SafeParceled(value = 4, subClass = WebImage.class)
public List<WebImage> images;
@SafeParceled(value = 5, subClass = String.class)
public List<String> namespaces;
@SafeParceled(6)
public String senderAppIdentifier;
@SafeParceled(7)
public Uri senderAppLaunchUri;
public String getApplicationId() {
return applicationId;
}
public List<WebImage> getImages() {
return images;
}
public String getName() {
return name;
}
public String getSenderAppIdentifier() {
return senderAppIdentifier;
}
public boolean isNamespaceSupported(String namespace) {
return namespaces.contains(namespace);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("ApplicationMetadata{");
sb.append("applicationId='").append(applicationId).append("'");
sb.append(", name='").append(name).append("'");
sb.append(", images=").append(images.toString());
if (namespaces != null) {
sb.append(", namespaces=").append(namespaces.toString());
}
sb.append(", senderAppIdentifier='").append(senderAppIdentifier).append("'");
if (senderAppLaunchUri != null) {
sb.append(", senderAppLaunchUri='").append(senderAppLaunchUri.toString()).append("'");
}
sb.append('}');
return sb.toString();
}
public static final Creator<ApplicationMetadata> CREATOR = new AutoCreator<ApplicationMetadata>(ApplicationMetadata.class);
}

View file

@ -0,0 +1,36 @@
/*
* 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 org.microg.safeparcel.AutoSafeParcelable;
import org.microg.safeparcel.SafeParceled;
public class ApplicationStatus extends AutoSafeParcelable {
public ApplicationStatus() {}
public ApplicationStatus(String applicationStatus) {
this.applicationStatus = applicationStatus;
}
@SafeParceled(1)
private int versionCode = 1;
@SafeParceled(2)
private String applicationStatus;
public static final Creator<ApplicationStatus> CREATOR = new AutoCreator<ApplicationStatus>(ApplicationStatus.class);
}

View file

@ -0,0 +1,223 @@
/*
* 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.CastApiClientBuilder;
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 CastApiClientBuilder());
/**
* 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

@ -0,0 +1,194 @@
/*
* 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 android.net.Uri;
import android.text.TextUtils;
import com.google.android.gms.common.images.WebImage;
import org.microg.gms.common.PublicApi;
import org.microg.safeparcel.AutoSafeParcelable;
import org.microg.safeparcel.SafeParceled;
import java.net.InetAddress;
import java.net.Inet4Address;
import java.util.ArrayList;
import java.util.List;
@PublicApi
public class CastDevice extends AutoSafeParcelable {
private static final String EXTRA_CAST_DEVICE = "com.google.android.gms.cast.EXTRA_CAST_DEVICE";
public CastDevice () {
}
public CastDevice (
String id, String name, InetAddress host, int port, String
deviceVersion, String friendlyName, String modelName, String
iconPath, int status, int capabilities) {
this.deviceId = id;
this.address = host.getHostAddress();
this.servicePort = port;
this.deviceVersion = deviceVersion;
this.friendlyName = friendlyName;
this.icons = new ArrayList<WebImage>();
this.icons.add(new WebImage(Uri.parse(String.format("http://%s:8008%s", this.address, iconPath))));
this.modelName = modelName;
this.capabilities = capabilities;
}
/**
* Video-output device capability.
*/
public static final int CAPABILITY_VIDEO_OUT = 1;
/**
* Video-input device capability.
*/
public static final int CAPABILITY_VIDEO_IN = 2;
/**
* Audio-output device capability.
*/
public static final int CAPABILITY_AUDIO_OUT = 4;
/**
* Audio-input device capability.
*/
public static final int CAPABILITY_AUDIO_IN = 8;
@SafeParceled(1)
private int versionCode = 3;
@SafeParceled(2)
private String deviceId;
@SafeParceled(3)
private String address;
@SafeParceled(4)
private String friendlyName;
@SafeParceled(5)
private String modelName;
@SafeParceled(6)
private String deviceVersion;
@SafeParceled(7)
private int servicePort;
@SafeParceled(value = 8, subClass = WebImage.class)
private ArrayList<WebImage> icons;
@SafeParceled(9)
private int capabilities;
@SafeParceled(10)
private int status;
@SafeParceled(11)
private String unknown; // TODO: Need to figure this one out
public String getDeviceId() {
return deviceId;
}
public String getDeviceVersion() {
return deviceVersion;
}
public String getFriendlyName() {
return friendlyName;
}
public static CastDevice getFromBundle(Bundle extras) {
if (extras == null) {
return null;
}
extras.setClassLoader(CastDevice.class.getClassLoader());
return extras.getParcelable(EXTRA_CAST_DEVICE);
}
public WebImage getIcon(int preferredWidth, int preferredHeight) {
return null;
}
public List<WebImage> getIcons() {
return icons;
}
public String getAddress() {
return address;
}
public String getModelName() {
return modelName;
}
public int getServicePort() {
return servicePort;
}
public boolean hasCapabilities(int[] capabilities) {
for (int capability : capabilities) {
if (!this.hasCapability(capability)) {
return false;
}
}
return true;
}
public boolean hasCapability(int capability) {
return (capability & capabilities) == capability;
}
public boolean hasIcons() {
return !icons.isEmpty();
}
public boolean isOnLocalNetwork() {
return false;
}
public boolean isSameDevice(CastDevice castDevice) {
return TextUtils.equals(castDevice.deviceId, deviceId);
}
public void putInBundle(Bundle bundle) {
bundle.putParcelable(EXTRA_CAST_DEVICE, this);
}
@Override
public String toString() {
return "CastDevice{" +
"deviceId=" + this.deviceId +
", address=" + address +
", friendlyName=" + friendlyName +
", modelName=" + modelName +
", deviceVersion=" + deviceVersion +
", servicePort=" + servicePort +
(icons == null ? "" : (", icons=" + icons.toString())) +
", capabilities=" + capabilities +
", status=" + status +
"}";
}
public static Creator<CastDevice> CREATOR = new AutoCreator<CastDevice>(CastDevice.class);
}

View file

@ -0,0 +1,49 @@
/*
* 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 org.microg.safeparcel.AutoSafeParcelable;
import org.microg.safeparcel.SafeParceled;
public class CastDeviceStatus extends AutoSafeParcelable {
public CastDeviceStatus() {
}
public CastDeviceStatus(double volume, boolean mute, int activeInputState, ApplicationMetadata applicationMetadata, int standbyState) {
this.volume = volume;
this.mute = mute;
this.activeInputState = activeInputState;
this.applicationMetadata = applicationMetadata;
this.standbyState = standbyState;
}
@SafeParceled(1)
private int versionCode = 1;
@SafeParceled(2)
private double volume;
@SafeParceled(3)
private boolean mute;
@SafeParceled(4)
private int activeInputState;
@SafeParceled(5)
private ApplicationMetadata applicationMetadata;
@SafeParceled(6)
private int standbyState;
public static final Creator<CastDeviceStatus> CREATOR = new AutoCreator<CastDeviceStatus>(CastDeviceStatus.class);
}

View file

@ -0,0 +1,145 @@
/*
* 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.text.TextUtils;
import java.util.Collection;
import java.util.Locale;
/**
* Intent constants for use with the Cast MediaRouteProvider. This class also contains utility methods for creating
* a control category for discovering Cast media routes that support a specific app and/or set of namespaces, to be
* used with MediaRouteSelector.
*/
public final class CastMediaControlIntent {
@Deprecated
public static final String CATEGORY_CAST = "com.google.android.gms.cast.CATEGORY_CAST";
public static final String ACTION_SYNC_STATUS = "com.google.android.gms.cast.ACTION_SYNC_STATUS";
/**
* The application ID for the Cast Default Media Receiver.
*/
public static final String DEFAULT_MEDIA_RECEIVER_APPLICATION_ID = "CC1AD845";
/**
* An error code indicating that a Cast request has failed.
*/
public static final int ERROR_CODE_REQUEST_FAILED = 1;
/**
* An error code indicating that the request could not be processed because the session could not be started.
*/
public static final int ERROR_CODE_SESSION_START_FAILED = 2;
/**
* An error code indicating that the connection to the Cast device has been lost, but the system is actively
* trying to re-establish the connection.
*/
public static final int ERROR_CODE_TEMPORARILY_DISCONNECTED = 3;
/**
* The extra that contains the ID of the application to launch for an
* {@link android.support.v7.media.MediaContolIntent#ACTION_START_SESSION} request.
* The value is expected to be a String.
*/
public static final String EXTRA_CAST_APPLICATION_ID = "com.google.android.gms.cast.EXTRA_CAST_APPLICATION_ID";
public static final String EXTRA_CAST_RELAUNCH_APPLICATION = "com.google.android.gms.cast.EXTRA_CAST_RELAUNCH_APPLICATION";
public static final String EXTRA_CAST_LANGUAGE_CODE = "com.google.android.gms.cast.EXTRA_CAST_LANGUAGE_CODE";
public static final String EXTRA_CAST_STOP_APPLICATION_WHEN_SESSION_ENDS = "com.google.android.gms.cast.EXTRA_CAST_STOP_APPLICATION_WHEN_SESSION_ENDS";
public static final String EXTRA_CUSTOM_DATA = "com.google.android.gms.cast.EXTRA_CUSTOM_DATA";
/**
* The extra that indicates whether debug logging should be enabled for the Cast session. The value is expected to be a boolean.
*/
public static final String EXTRA_DEBUG_LOGGING_ENABLED = "com.google.android.gms.cast.EXTRA_DEBUG_LOGGING_ENABLED";
/**
* n error bundle extra for the error code. The value is an integer, and will be one of the {@code ERROR_CODE_*}
* constants declared in this class.
*/
public static final String EXTRA_ERROR_CODE = "com.google.android.gms.cast.EXTRA_ERROR_CODE";
public static final String CATEGORY_CAST_REMOTE_PLAYBACK = "com.google.android.gms.cast.CATEGORY_CAST_REMOTE_PLAYBACK";
private CastMediaControlIntent() {
}
/**
* Returns a custom control category for discovering Cast devices that support running the specified app, independent of whether the app is running or not.
*
* @param applicationId The application ID of the receiver application.
*/
public static String categoryForCast(String applicationId) {
return CATEGORY_CAST + "/" + applicationId;
}
/**
* Returns true if the given category is a custom control category for cast devices, specific to an application ID.
*
* @param applicationId The application ID of the receiver application.
*/
public static boolean isCategoryForCast(String category) {
if (category == null) {
return false;
}
return category.startsWith(CATEGORY_CAST + "/");
}
/**
* Returns a custom control category for discovering Cast devices meeting both application ID and namespace
* restrictions. See {@link #categoryForCast(Collection)} and {@link #categoryForCast(String)} for more details.
*/
public static String categoryForCast(String applicationId, Collection<String> namespaces) {
return CATEGORY_CAST + "" + applicationId + "/" + TextUtils.join(",", namespaces);
}
/**
* Returns a custom control category for discovering Cast devices currently running an application which supports the specified namespaces. Apps supporting additional namespaces beyond those specified here are still considered supported.
*/
public static String categoryForCast(Collection<String> namespaces) {
return CATEGORY_CAST + "//" + TextUtils.join(",", namespaces);
}
/**
* Returns a custom control category for discovering Cast devices which support the default Android remote
* playback actions using the specified Cast player. If the Default Media Receiver is desired, use
* {@link #DEFAULT_MEDIA_RECEIVER_APPLICATION_ID} as the applicationId.
*
* @param applicationId The application ID of the receiver application.
*/
public static String categoryForRemotePlayback(String applicationId) {
return CATEGORY_CAST_REMOTE_PLAYBACK + "/" + applicationId;
}
/**
* Returns a custom control category for discovering Cast devices which support the Default Media Receiver.
*/
public static String categoryForRemotePlayback() {
return CATEGORY_CAST_REMOTE_PLAYBACK;
}
/**
* Returns an RFC-5646 language tag string fo the given locale.
*/
public static String languageTagForLocale(Locale locale) {
StringBuilder sb = new StringBuilder(locale.getLanguage());
if (!TextUtils.isEmpty(locale.getCountry())) sb.append('-').append(locale.getCountry());
if (!TextUtils.isEmpty(locale.getVariant())) sb.append('-').append(locale.getVariant());
return sb.toString();
}
}

View file

@ -0,0 +1,33 @@
/*
* 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

@ -0,0 +1,76 @@
/*
* 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.CastRemoteDisplayApiClientBuilder;
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 CastRemoteDisplayApiClientBuilder());
/**
* 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

@ -0,0 +1,26 @@
/*
* 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

@ -0,0 +1,28 @@
/*
* 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

@ -0,0 +1,38 @@
/*
* 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;
public final class CastStatusCodes {
public static final int APPLICATION_NOT_FOUND = 2004;
public static final int APPLICATION_NOT_RUNNING = 2005;
public static final int AUTHENTICATION_FAILED = 2000;
public static final int CANCELED = 2002;
public static final int ERROR_SERVICE_CREATION_FAILED = 2200;
public static final int ERROR_SERVICE_DISCONNECTED = 2201;
public static final int FAILED = 2100;
public static final int INTERNAL_ERROR = 8;
public static final int INTERRUPTED = 14;
public static final int INVALID_REQUEST = 2001;
public static final int MESSAGE_SEND_BUFFER_TOO_FULL = 2007;
public static final int MESSAGE_TOO_LARGE = 2006;
public static final int NETWORK_ERROR = 7;
public static final int NOT_ALLOWED = 2003;
public static final int REPLACED = 2103;
public static final int SUCCESS = 0;
public static final int TIMEOUT = 15;
public static final int UNKNOWN_ERROR = 13;
}

View file

@ -0,0 +1,76 @@
/*
* SPDX-FileCopyrightText: 2023 microG Project Team
* SPDX-License-Identifier: Apache-2.0
* Notice: Portions of this file are reproduced from work created and shared by Google and used
* according to terms described in the Creative Commons 4.0 Attribution License.
* See https://developers.google.com/readme/policies for details.
*/
package com.google.android.gms.cast;
import android.os.Parcel;
import com.google.android.gms.common.internal.safeparcel.AbstractSafeParcelable;
import com.google.android.gms.common.internal.safeparcel.SafeParcelable;
import com.google.android.gms.common.internal.safeparcel.SafeParcelableCreatorAndWriter;
/**
* Credentials data used to identify the credentials of the sender.
*/
@SafeParcelable.Class
public class CredentialsData extends AbstractSafeParcelable {
/**
* The credentials type indicating it comes from an Android sender.
*/
public static final String CREDENTIALS_TYPE_ANDROID = "android";
/**
* The credentials type indicating it comes from the cloud (i.e. assistant).
*/
public static final String CREDENTIALS_TYPE_CLOUD = "cloud";
/**
* The credentials type indicating it comes from an iOS sender.
*/
public static final String CREDENTIALS_TYPE_IOS = "ios";
/**
* The credentials type indicating it comes from a Web sender.
*/
public static final String CREDENTIALS_TYPE_WEB = "web";
@Field(1)
final String credentials;
@Field(2)
final String credentialsType;
@Constructor
CredentialsData(@Param(1) String credentials, @Param(2) String credentialsType) {
this.credentials = credentials;
this.credentialsType = credentialsType;
}
/**
* Returns the application-specific blob which identifies and possibly authenticates the user that's requesting to launch
* or join an receiver app. This field may be {@code null}.
* <p>
* For requests sent from Assistant, it is an OAuth 2 token.
* <p>
* For requests sent from mobile senders, it is set by sender apps.
*/
public String getCredentials() {
return credentials;
}
/**
* Returns the type of the credentials. This field may be {@code null}.
* <p>
* This could be one of the {@code CREDENTIALS_TYPE_*} constants or custom-defined.
*/
public String getCredentialsType() {
return credentialsType;
}
@Override
public void writeToParcel(Parcel out, int flags) {
CREATOR.writeToParcel(this, out, flags);
}
public static final SafeParcelableCreatorAndWriter<CredentialsData> CREATOR = findCreator(CredentialsData.class);
}

View file

@ -0,0 +1,29 @@
/*
* 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 org.microg.safeparcel.AutoSafeParcelable;
import org.microg.safeparcel.SafeParceled;
public class JoinOptions extends AutoSafeParcelable {
@SafeParceled(1)
private int versionCode = 1;
@SafeParceled(2)
private int connectionType = 0;
public static Creator<JoinOptions> CREATOR = new AutoCreator<JoinOptions>(JoinOptions.class);
}

View file

@ -0,0 +1,104 @@
/*
* SPDX-FileCopyrightText: 2015 microG Project Team
* SPDX-License-Identifier: Apache-2.0
* Notice: Portions of this file are reproduced from work created and shared by Google and used
* according to terms described in the Creative Commons 4.0 Attribution License.
* See https://developers.google.com/readme/policies for details.
*/
package com.google.android.gms.cast;
import androidx.annotation.NonNull;
import com.google.android.gms.common.api.GoogleApiClient;
import org.microg.gms.utils.ToStringHelper;
import org.microg.safeparcel.AutoSafeParcelable;
import java.util.Locale;
/**
* An object that holds options that affect how a receiver application is launched. See
* {@link Cast.CastApi#launchApplication(GoogleApiClient, String, LaunchOptions)}.
*/
public class LaunchOptions extends AutoSafeParcelable {
@Field(1)
private int versionCode = 1;
@Field(2)
private boolean relaunchIfRunning = false;
@Field(3)
private String language;
@Field(4)
private boolean androidReceiverCompatible = false;
@Field(5)
private CredentialsData credentialsData = null;
/**
* The constructor of {@link LaunchOptions}.
*/
public LaunchOptions() {
Locale locale = Locale.getDefault();
StringBuilder sb = new StringBuilder(locale.getLanguage());
if (!locale.getCountry().isEmpty()) {
sb.append("-").append(locale.getCountry());
}
if (!locale.getVariant().isEmpty()) {
sb.append("-").append(locale.getVariant());
}
language = sb.toString();
}
/**
* Returns {@code true} if the sender app supports casting to an Android TV app.
*/
public boolean getAndroidReceiverCompatible() {
return androidReceiverCompatible;
}
/**
* Returns the {@link CredentialsData}.
*/
public CredentialsData getCredentialsData() {
return credentialsData;
}
/**
* Returns the language, or {@code null} if none was specified.
*/
public String getLanguage() {
return language;
}
/**
* Returns the "relaunch if running" flag.
*/
public boolean getRelaunchIfRunning() {
return relaunchIfRunning;
}
/**
* Sets the language to be used by the receiver application. If not specified, the sender device's default language is used.
*
* @param language The language
*/
public void setLanguage(String language) {
this.language = language;
}
/**
* Sets the "relaunch if running" flag. If the flag is set, the receiver application will be relaunched even if it is already running. The flag is not set by default.
*/
public void setRelaunchIfRunning(boolean relaunchIfRunning) {
this.relaunchIfRunning = relaunchIfRunning;
}
@NonNull
@Override
public String toString() {
return ToStringHelper.name("LaunchOptions")
.field("relaunchIfRunning", relaunchIfRunning)
.field("language", language)
.field("androidReceiverCompatible", androidReceiverCompatible)
.end();
}
public static Creator<LaunchOptions> CREATOR = new AutoCreator<LaunchOptions>(LaunchOptions.class);
}

View file

@ -0,0 +1,22 @@
/*
* SPDX-FileCopyrightText: 2021, microG Project Team
* SPDX-License-Identifier: Apache-2.0
*/
package com.google.android.gms.cast;
import org.microg.safeparcel.AutoSafeParcelable;
import org.microg.safeparcel.SafeParceled;
public class RequestItem extends AutoSafeParcelable {
@Field(2)
public String url;
@Field(3)
public int protocolType;
@Field(4)
public int initialTime;
@Field(5)
public String hlsSegmentFormat;
public static Creator<RequestItem> CREATOR = new AutoCreator<RequestItem>(RequestItem.class);
}

View file

@ -0,0 +1,11 @@
/*
* SPDX-FileCopyrightText: 2022 microG Project Team
* SPDX-License-Identifier: CC-BY-4.0
* Notice: Portions of this file are reproduced from work created and shared by Google and used
* according to terms described in the Creative Commons 4.0 Attribution License.
* See https://developers.google.com/readme/policies for details.
*/
/**
* Contains classes for interacting with Google Cast devices.
*/
package com.google.android.gms.cast;

View file

@ -0,0 +1,35 @@
/*
* 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.Api;
import org.microg.gms.common.api.ApiClientBuilder;
import com.google.android.gms.common.internal.ClientSettings;
import com.google.android.gms.common.api.internal.ConnectionCallbacks;
import com.google.android.gms.common.api.internal.OnConnectionFailedListener;
public class CastApiClientBuilder implements ApiClientBuilder<Cast.CastOptions> {
@Override
public Api.Client build(Cast.CastOptions options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {
return new CastClientImpl(context, options, callbacks, connectionFailedListener);
}
}

View file

@ -0,0 +1,134 @@
/*
* 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

@ -0,0 +1,30 @@
/*
* 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 org.microg.gms.common.DummyApiClient;
import com.google.android.gms.common.api.internal.ConnectionCallbacks;
import com.google.android.gms.common.api.internal.OnConnectionFailedListener;
public class CastClientImpl extends DummyApiClient {
public CastClientImpl(Context context, Cast.CastOptions options, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {
}
}

View file

@ -0,0 +1,36 @@
/*
* 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.Api;
import org.microg.gms.common.DummyApiClient;
import org.microg.gms.common.api.ApiClientBuilder;
import com.google.android.gms.common.internal.ClientSettings;
import com.google.android.gms.common.api.internal.ConnectionCallbacks;
import com.google.android.gms.common.api.internal.OnConnectionFailedListener;
public class CastRemoteDisplayApiClientBuilder implements ApiClientBuilder<CastRemoteDisplay.CastRemoteDisplayOptions> {
@Override
public Api.Client build(CastRemoteDisplay.CastRemoteDisplayOptions options, Context context, Looper looper, ClientSettings clientSettings, ConnectionCallbacks callbacks, OnConnectionFailedListener connectionFailedListener) {
return new DummyApiClient();
}
}

View file

@ -0,0 +1,34 @@
/*
* 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;
}
}