mirror of
https://github.com/TeamVanced/VancedMicroG
synced 2025-01-23 17:37:31 +01:00
commit
a80b263656
1
.gitignore
vendored
1
.gitignore
vendored
@ -3,6 +3,7 @@ gen/
|
||||
bin/
|
||||
build/
|
||||
.gradle/
|
||||
.idea/
|
||||
user.gradle
|
||||
local.properties
|
||||
.directory
|
||||
|
@ -23,15 +23,27 @@ def useMapbox() {
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation 'com.android.support:multidex:1.0.3'
|
||||
implementation "com.android.support:support-v4:$supportLibraryVersion"
|
||||
implementation "com.android.support:appcompat-v7:$supportLibraryVersion"
|
||||
implementation "com.android.support:mediarouter-v7:$supportLibraryVersion"
|
||||
implementation "com.squareup.wire:wire-runtime:1.6.1"
|
||||
implementation "com.takisoft.fix:preference-v7:$supportLibraryVersion.0"
|
||||
implementation "de.hdodenhof:circleimageview:1.3.0"
|
||||
implementation "org.conscrypt:conscrypt-android:2.0.0"
|
||||
// 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"
|
||||
|
||||
// Specified manually due to
|
||||
// https://github.com/vitalidze/chromecast-java-api-v2/issues/91
|
||||
api "org.slf4j:slf4j-api:1.7.25"
|
||||
api "uk.uuid.slf4j:slf4j-android:1.7.25-1"
|
||||
|
||||
implementation project(':microg-ui-tools')
|
||||
implementation project(':play-services-api')
|
||||
implementation project(':play-services-cast-api')
|
||||
implementation project(':play-services-wearable')
|
||||
implementation project(':unifiednlp-base')
|
||||
implementation project(':wearable-lib')
|
||||
@ -76,6 +88,8 @@ android {
|
||||
minSdkVersion androidMinSdk()
|
||||
targetSdkVersion androidTargetSdk()
|
||||
|
||||
multiDexEnabled true
|
||||
|
||||
ndk {
|
||||
abiFilters "armeabi", "armeabi-v7a", "arm64-v8a", "x86", "x86_64"
|
||||
}
|
||||
@ -102,6 +116,10 @@ android {
|
||||
sourceCompatibility JavaVersion.VERSION_1_8
|
||||
targetCompatibility JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
packagingOptions {
|
||||
exclude 'META-INF/ASL2.0'
|
||||
}
|
||||
}
|
||||
|
||||
if (file('user.gradle').exists()) {
|
||||
|
@ -92,13 +92,22 @@
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.CHANGE_DEVICE_IDLE_TEMP_WHITELIST" tools:ignore="ProtectedPermissions"/>
|
||||
|
||||
<uses-sdk tools:overrideLibrary="com.takisoft.fix.support.v7.preference,android.support.graphics.drawable.animated,android.arch.lifecycle,android.arch.lifecycle.livedata.core,android.arch.lifecycle.viewmodel,android.arch.core"/>
|
||||
<uses-sdk tools:overrideLibrary="
|
||||
com.takisoft.fix.support.v7.preference,
|
||||
android.support.graphics.drawable.animated,
|
||||
android.arch.lifecycle,
|
||||
android.arch.lifecycle.livedata.core,
|
||||
android.arch.lifecycle.viewmodel,
|
||||
android.arch.core,
|
||||
android.support.v7.mediarouter,
|
||||
android.support.v7.palette" />
|
||||
|
||||
<application
|
||||
android:allowBackup="false"
|
||||
android:extractNativeLibs="false"
|
||||
android:icon="@mipmap/ic_core_service_app"
|
||||
android:label="@string/gms_app_name">
|
||||
android:label="@string/gms_app_name"
|
||||
android:name="android.support.multidex.MultiDexApplication">
|
||||
<meta-data
|
||||
android:name="fake-signature"
|
||||
android:value="@string/fake_signature"/>
|
||||
@ -392,6 +401,14 @@
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<!-- Cast -->
|
||||
|
||||
<service android:name="com.google.android.gms.cast.media.CastMediaRouteProviderService">
|
||||
<intent-filter>
|
||||
<action android:name="android.media.MediaRouteProviderService" />
|
||||
</intent-filter>
|
||||
</service>
|
||||
|
||||
<!-- Chimera spoof -->
|
||||
<provider
|
||||
android:name="org.microg.gms.ChimeraSpoofProvider"
|
||||
@ -611,6 +628,12 @@
|
||||
</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>
|
||||
|
||||
<service android:name="org.microg.gms.DummyService">
|
||||
<intent-filter>
|
||||
<action android:name="com.google.android.gms.plus.service.START"/>
|
||||
@ -619,7 +642,6 @@
|
||||
<action android:name="com.google.android.gms.appstate.service.START"/>
|
||||
<action android:name="com.google.android.gms.ads.service.START"/>
|
||||
<action android:name="com.google.android.gms.accounts.ACCOUNT_SERVICE"/>
|
||||
<action android:name="com.google.android.gms.cast.service.BIND_CAST_DEVICE_CONTROLLER_SERVICE"/>
|
||||
<action android:name="com.google.android.gms.identity.service.BIND"/>
|
||||
<action android:name="com.google.android.gms.wearable.BIND"/>
|
||||
<action android:name="com.google.android.gms.auth.service.START"/>
|
||||
|
@ -0,0 +1,154 @@
|
||||
/*
|
||||
* 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.framework.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v7.media.MediaControlIntent;
|
||||
import android.support.v7.media.MediaRouteSelector;
|
||||
import android.support.v7.media.MediaRouter;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.CastMediaControlIntent;
|
||||
import com.google.android.gms.cast.framework.CastOptions;
|
||||
import com.google.android.gms.cast.framework.IAppVisibilityListener;
|
||||
import com.google.android.gms.cast.framework.ICastContext;
|
||||
import com.google.android.gms.cast.framework.IDiscoveryManager;
|
||||
import com.google.android.gms.cast.framework.ISessionManager;
|
||||
import com.google.android.gms.cast.framework.ISessionProvider;
|
||||
import com.google.android.gms.dynamic.IObjectWrapper;
|
||||
import com.google.android.gms.dynamic.ObjectWrapper;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class CastContextImpl extends ICastContext.Stub {
|
||||
private static final String TAG = CastContextImpl.class.getSimpleName();
|
||||
|
||||
private SessionManagerImpl sessionManager;
|
||||
private DiscoveryManagerImpl discoveryManager;
|
||||
|
||||
private Context context;
|
||||
private CastOptions options;
|
||||
private IMediaRouter router;
|
||||
private Map<String, ISessionProvider> sessionProviders = new HashMap<String, ISessionProvider>();
|
||||
public ISessionProvider defaultSessionProvider;
|
||||
|
||||
private MediaRouteSelector mergedSelector;
|
||||
|
||||
public CastContextImpl(IObjectWrapper context, CastOptions options, IMediaRouter router, Map<String, IBinder> sessionProviders) throws RemoteException {
|
||||
this.context = (Context) ObjectWrapper.unwrap(context);
|
||||
this.options = options;
|
||||
this.router = router;
|
||||
for (Map.Entry<String, IBinder> entry : sessionProviders.entrySet()) {
|
||||
this.sessionProviders.put(entry.getKey(), ISessionProvider.Stub.asInterface(entry.getValue()));
|
||||
}
|
||||
|
||||
String receiverApplicationId = options.getReceiverApplicationId();
|
||||
String defaultCategory = CastMediaControlIntent.categoryForCast(receiverApplicationId);
|
||||
|
||||
this.defaultSessionProvider = this.sessionProviders.get(defaultCategory);
|
||||
|
||||
// TODO: This should incorporate passed options
|
||||
this.mergedSelector = new MediaRouteSelector.Builder()
|
||||
.addControlCategory(MediaControlIntent.CATEGORY_LIVE_VIDEO)
|
||||
.addControlCategory(MediaControlIntent.CATEGORY_REMOTE_PLAYBACK)
|
||||
.addControlCategory(defaultCategory)
|
||||
.build();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Bundle getMergedSelectorAsBundle() throws RemoteException {
|
||||
return this.mergedSelector.asBundle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addVisibilityChangeListener(IAppVisibilityListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: addVisibilityChangeListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeVisibilityChangeListener(IAppVisibilityListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: removeVisibilityChangeListener");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isApplicationVisible() throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: isApplicationVisible");
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionManagerImpl getSessionManagerImpl() {
|
||||
if (this.sessionManager == null) {
|
||||
this.sessionManager = new SessionManagerImpl(this);
|
||||
}
|
||||
return this.sessionManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IDiscoveryManager getDiscoveryManagerImpl() throws RemoteException {
|
||||
if (this.discoveryManager == null) {
|
||||
this.discoveryManager = new DiscoveryManagerImpl(this);
|
||||
}
|
||||
return this.discoveryManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void destroy() throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: destroy");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityResumed(IObjectWrapper activity) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onActivityResumed");
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActivityPaused(IObjectWrapper activity) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: onActivityPaused");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setReceiverApplicationId(String receiverApplicationId, Map sessionProvidersByCategory) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: setReceiverApplicationId");
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return this.context;
|
||||
}
|
||||
|
||||
public IMediaRouter getRouter() {
|
||||
return this.router;
|
||||
}
|
||||
|
||||
public MediaRouteSelector getMergedSelector() {
|
||||
return this.mergedSelector;
|
||||
}
|
||||
|
||||
public CastOptions getOptions() {
|
||||
return this.options;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IObjectWrapper getWrappedThis() throws RemoteException {
|
||||
return ObjectWrapper.wrap(this);
|
||||
}
|
||||
}
|
@ -16,7 +16,9 @@
|
||||
|
||||
package com.google.android.gms.cast.framework.internal;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.RemoteException;
|
||||
import android.support.v7.media.MediaRouter;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.framework.CastOptions;
|
||||
@ -27,6 +29,10 @@ import com.google.android.gms.cast.framework.IReconnectionService;
|
||||
import com.google.android.gms.cast.framework.ISession;
|
||||
import com.google.android.gms.cast.framework.ISessionProxy;
|
||||
import com.google.android.gms.cast.framework.media.CastMediaOptions;
|
||||
import com.google.android.gms.cast.framework.internal.CastContextImpl;
|
||||
import com.google.android.gms.cast.framework.internal.CastSessionImpl;
|
||||
import com.google.android.gms.cast.framework.internal.MediaRouterCallbackImpl;
|
||||
import com.google.android.gms.cast.framework.internal.SessionImpl;
|
||||
import com.google.android.gms.cast.framework.media.IMediaNotificationService;
|
||||
import com.google.android.gms.cast.framework.media.internal.IFetchBitmapTask;
|
||||
import com.google.android.gms.cast.framework.media.internal.IFetchBitmapTaskProgressPublisher;
|
||||
@ -38,21 +44,18 @@ public class CastDynamiteModuleImpl extends ICastDynamiteModule.Stub {
|
||||
private static final String TAG = CastDynamiteModuleImpl.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public ICastContext newCastContextImpl(IObjectWrapper context, CastOptions options, IMediaRouter router, Map map) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: newCastContextImpl");
|
||||
return null;
|
||||
public ICastContext newCastContextImpl(IObjectWrapper context, CastOptions options, IMediaRouter router, Map sessionProviders) throws RemoteException {
|
||||
return new CastContextImpl(context, options, router, sessionProviders);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ISession newSessionImpl(String s1, String s2, ISessionProxy proxy) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: newSessionImpl");
|
||||
return null;
|
||||
public ISession newSessionImpl(String category, String sessionId, ISessionProxy proxy) throws RemoteException {
|
||||
return new SessionImpl(category, sessionId, proxy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ICastSession newCastSessionImpl(CastOptions options, IObjectWrapper session, ICastConnectionController controller) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: newCastSessionImpl");
|
||||
return null;
|
||||
return new CastSessionImpl(options, session, controller);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -0,0 +1,79 @@
|
||||
/*
|
||||
* 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.framework.internal;
|
||||
|
||||
import com.google.android.gms.cast.framework.ICastSession;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.ApplicationMetadata;
|
||||
import com.google.android.gms.cast.framework.CastOptions;
|
||||
import com.google.android.gms.cast.framework.ICastConnectionController;
|
||||
import com.google.android.gms.common.api.Status;
|
||||
import com.google.android.gms.dynamic.IObjectWrapper;
|
||||
import com.google.android.gms.dynamic.ObjectWrapper;
|
||||
|
||||
public class CastSessionImpl extends ICastSession.Stub {
|
||||
private static final String TAG = CastSessionImpl.class.getSimpleName();
|
||||
private CastOptions options;
|
||||
private SessionImpl session;
|
||||
private ICastConnectionController controller;
|
||||
|
||||
public CastSessionImpl(CastOptions options, IObjectWrapper session, ICastConnectionController controller) throws RemoteException {
|
||||
this.options = options;
|
||||
this.session = (SessionImpl) ObjectWrapper.unwrap(session);
|
||||
this.controller = controller;
|
||||
|
||||
this.session.setCastSession(this);
|
||||
}
|
||||
|
||||
public void launchApplication() throws RemoteException {
|
||||
this.controller.launchApplication(this.options.getReceiverApplicationId(), this.options.getLaunchOptions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnected(Bundle routeInfoExtra) throws RemoteException {
|
||||
this.controller.launchApplication(this.options.getReceiverApplicationId(), this.options.getLaunchOptions());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionSuspended(int reason) {
|
||||
Log.d(TAG, "unimplemented Method: onConnectionSuspended");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConnectionFailed(Status status) {
|
||||
Log.d(TAG, "unimplemented Method: onConnectionFailed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationConnectionSuccess(ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) {
|
||||
this.session.onApplicationConnectionSuccess(applicationMetadata, applicationStatus, sessionId, wasLaunched);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApplicationConnectionFailure(int statusCode) {
|
||||
this.session.onApplicationConnectionFailure(statusCode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void disconnectFromDevice(boolean boolean1, int int1) {
|
||||
Log.d(TAG, "unimplemented Method: disconnectFromDevice");
|
||||
}
|
||||
}
|
@ -0,0 +1,68 @@
|
||||
/*
|
||||
* 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.framework.internal;
|
||||
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.framework.IDiscoveryManager;
|
||||
import com.google.android.gms.cast.framework.IDiscoveryManagerListener;
|
||||
import com.google.android.gms.cast.framework.internal.CastContextImpl;
|
||||
import com.google.android.gms.dynamic.IObjectWrapper;
|
||||
import com.google.android.gms.dynamic.ObjectWrapper;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
public class DiscoveryManagerImpl extends IDiscoveryManager.Stub {
|
||||
private static final String TAG = DiscoveryManagerImpl.class.getSimpleName();
|
||||
|
||||
private CastContextImpl castContextImpl;
|
||||
|
||||
private Set discoveryManagerListeners = new HashSet();
|
||||
|
||||
public DiscoveryManagerImpl(CastContextImpl castContextImpl) {
|
||||
this.castContextImpl = castContextImpl;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startDiscovery() {
|
||||
Log.d(TAG, "unimplemented Method: startDiscovery");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void stopDiscovery() {
|
||||
Log.d(TAG, "unimplemented Method: stopDiscovery");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addDiscoveryManagerListener(IDiscoveryManagerListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: addDiscoveryManagerListener");
|
||||
this.discoveryManagerListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeDiscoveryManagerListener(IDiscoveryManagerListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: removeDiscoveryManagerListener");
|
||||
this.discoveryManagerListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IObjectWrapper getWrappedThis() throws RemoteException {
|
||||
return ObjectWrapper.wrap(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.framework.internal;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.CastDevice;
|
||||
import com.google.android.gms.cast.framework.ISession;
|
||||
import com.google.android.gms.dynamic.IObjectWrapper;
|
||||
import com.google.android.gms.dynamic.ObjectWrapper;
|
||||
|
||||
import android.support.v7.media.MediaControlIntent;
|
||||
|
||||
public class MediaRouterCallbackImpl extends IMediaRouterCallback.Stub {
|
||||
private static final String TAG = MediaRouterCallbackImpl.class.getSimpleName();
|
||||
|
||||
private CastContextImpl castContext;
|
||||
|
||||
public MediaRouterCallbackImpl(CastContextImpl castContext) {
|
||||
this.castContext = castContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRouteAdded(String routeId, Bundle extras) {
|
||||
Log.d(TAG, "unimplemented Method: onRouteAdded");
|
||||
}
|
||||
@Override
|
||||
public void onRouteChanged(String routeId, Bundle extras) {
|
||||
Log.d(TAG, "unimplemented Method: onRouteChanged");
|
||||
}
|
||||
@Override
|
||||
public void onRouteRemoved(String routeId, Bundle extras) {
|
||||
Log.d(TAG, "unimplemented Method: onRouteRemoved");
|
||||
}
|
||||
@Override
|
||||
public void onRouteSelected(String routeId, Bundle extras) throws RemoteException {
|
||||
CastDevice castDevice = CastDevice.getFromBundle(extras);
|
||||
|
||||
SessionImpl session = (SessionImpl) ObjectWrapper.unwrap(this.castContext.defaultSessionProvider.getSession(null));
|
||||
Bundle routeInfoExtras = this.castContext.getRouter().getRouteInfoExtrasById(routeId);
|
||||
if (routeInfoExtras != null) {
|
||||
session.start(this.castContext, castDevice, routeId, routeInfoExtras);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void unknown(String routeId, Bundle extras) {
|
||||
Log.d(TAG, "unimplemented Method: unknown");
|
||||
}
|
||||
@Override
|
||||
public void onRouteUnselected(String routeId, Bundle extras, int reason) {
|
||||
Log.d(TAG, "unimplemented Method: onRouteUnselected");
|
||||
}
|
||||
}
|
@ -0,0 +1,197 @@
|
||||
/*
|
||||
* 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.framework.internal;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
|
||||
import com.google.android.gms.cast.ApplicationMetadata;
|
||||
import com.google.android.gms.cast.CastDevice;
|
||||
import com.google.android.gms.cast.framework.ISession;
|
||||
import com.google.android.gms.cast.framework.ISessionProxy;
|
||||
import com.google.android.gms.dynamic.IObjectWrapper;
|
||||
import com.google.android.gms.dynamic.ObjectWrapper;
|
||||
|
||||
public class SessionImpl extends ISession.Stub {
|
||||
private static final String TAG = SessionImpl.class.getSimpleName();
|
||||
|
||||
private String category;
|
||||
private String sessionId;
|
||||
private ISessionProxy proxy;
|
||||
|
||||
private CastSessionImpl castSession;
|
||||
|
||||
private CastContextImpl castContext;
|
||||
private CastDevice castDevice;
|
||||
private Bundle routeInfoExtra;
|
||||
|
||||
private boolean mIsConnecting = false;
|
||||
private boolean mIsConnected = false;
|
||||
private String routeId = null;
|
||||
|
||||
public SessionImpl(String category, String sessionId, ISessionProxy proxy) {
|
||||
this.category = category;
|
||||
this.sessionId = sessionId;
|
||||
this.proxy = proxy;
|
||||
}
|
||||
|
||||
public void start(CastContextImpl castContext, CastDevice castDevice, String routeId, Bundle routeInfoExtra) throws RemoteException {
|
||||
this.castContext = castContext;
|
||||
this.castDevice = castDevice;
|
||||
this.routeInfoExtra = routeInfoExtra;
|
||||
this.routeId = routeId;
|
||||
|
||||
this.mIsConnecting = true;
|
||||
this.mIsConnected = false;
|
||||
this.castContext.getSessionManagerImpl().onSessionStarting(this);
|
||||
this.proxy.start(routeInfoExtra);
|
||||
}
|
||||
|
||||
public void onApplicationConnectionSuccess(ApplicationMetadata applicationMetadata, String applicationStatus, String sessionId, boolean wasLaunched) {
|
||||
this.mIsConnecting = false;
|
||||
this.mIsConnected = true;
|
||||
this.castContext.getSessionManagerImpl().onSessionStarted(this, sessionId);
|
||||
try {
|
||||
this.castContext.getRouter().selectRouteById(this.getRouteId());
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "Error calling selectRouteById: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void onApplicationConnectionFailure(int statusCode) {
|
||||
this.mIsConnecting = false;
|
||||
this.mIsConnected = false;
|
||||
this.routeId = null;
|
||||
this.castContext = null;
|
||||
this.castDevice = null;
|
||||
this.routeInfoExtra = null;
|
||||
this.castContext.getSessionManagerImpl().onSessionStartFailed(this, statusCode);
|
||||
try {
|
||||
this.castContext.getRouter().selectDefaultRoute();
|
||||
} catch (RemoteException ex) {
|
||||
Log.e(TAG, "Error calling selectDefaultRoute: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public void onRouteSelected(Bundle extras) {
|
||||
}
|
||||
|
||||
public CastSessionImpl getCastSession() {
|
||||
return this.castSession;
|
||||
}
|
||||
|
||||
public void setCastSession(CastSessionImpl castSession) {
|
||||
this.castSession = castSession;
|
||||
}
|
||||
|
||||
public ISessionProxy getSessionProxy() {
|
||||
return this.proxy;
|
||||
}
|
||||
|
||||
public IObjectWrapper getWrappedSession() throws RemoteException {
|
||||
if (this.proxy == null) {
|
||||
return ObjectWrapper.wrap(null);
|
||||
}
|
||||
return this.proxy.getWrappedSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCategory() {
|
||||
return this.category;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getSessionId() {
|
||||
return this.sessionId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRouteId() {
|
||||
return this.routeId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnected() {
|
||||
return this.mIsConnected;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isConnecting() {
|
||||
return this.mIsConnecting;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisconnecting() {
|
||||
Log.d(TAG, "unimplemented Method: isDisconnecting");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDisconnected() {
|
||||
Log.d(TAG, "unimplemented Method: isDisconnected");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResuming() {
|
||||
Log.d(TAG, "unimplemented Method: isResuming");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSuspended() {
|
||||
Log.d(TAG, "unimplemented Method: isSuspended");
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySessionStarted(String sessionId) {
|
||||
Log.d(TAG, "unimplemented Method: notifySessionStarted");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyFailedToStartSession(int error) {
|
||||
Log.d(TAG, "unimplemented Method: notifyFailedToStartSession");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySessionEnded(int error) {
|
||||
Log.d(TAG, "unimplemented Method: notifySessionEnded");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySessionResumed(boolean wasSuspended) {
|
||||
Log.d(TAG, "unimplemented Method: notifySessionResumed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyFailedToResumeSession(int error) {
|
||||
Log.d(TAG, "unimplemented Method: notifyFailedToResumeSession");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifySessionSuspended(int reason) {
|
||||
Log.d(TAG, "unimplemented Method: notifySessionSuspended");
|
||||
}
|
||||
|
||||
@Override
|
||||
public IObjectWrapper getWrappedObject() {
|
||||
return ObjectWrapper.wrap(this);
|
||||
}
|
||||
}
|
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* 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.framework.internal;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.os.RemoteException;
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.android.gms.cast.framework.CastState;
|
||||
import com.google.android.gms.cast.framework.ICastStateListener;
|
||||
import com.google.android.gms.cast.framework.ISession;
|
||||
import com.google.android.gms.cast.framework.ISessionManager;
|
||||
import com.google.android.gms.cast.framework.ISessionManagerListener;
|
||||
import com.google.android.gms.cast.framework.internal.CastContextImpl;
|
||||
import com.google.android.gms.cast.framework.internal.SessionImpl;
|
||||
import com.google.android.gms.dynamic.IObjectWrapper;
|
||||
import com.google.android.gms.dynamic.ObjectWrapper;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.HashSet;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.HashMap;
|
||||
|
||||
public class SessionManagerImpl extends ISessionManager.Stub {
|
||||
private static final String TAG = SessionManagerImpl.class.getSimpleName();
|
||||
|
||||
private CastContextImpl castContext;
|
||||
|
||||
private Set<ISessionManagerListener> sessionManagerListeners = new HashSet<ISessionManagerListener>();
|
||||
private Set<ICastStateListener> castStateListeners = new HashSet<ICastStateListener>();
|
||||
|
||||
private Map<String, SessionImpl> routeSessions = new HashMap<String, SessionImpl>();
|
||||
|
||||
private SessionImpl currentSession;
|
||||
|
||||
private int castState = CastState.NO_DEVICES_AVAILABLE;
|
||||
|
||||
public SessionManagerImpl(CastContextImpl castContext) {
|
||||
this.castContext = castContext;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IObjectWrapper getWrappedCurrentSession() throws RemoteException {
|
||||
if (this.currentSession == null) {
|
||||
return ObjectWrapper.wrap(null);
|
||||
}
|
||||
return this.currentSession.getWrappedSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endCurrentSession(boolean b, boolean stopCasting) throws RemoteException {
|
||||
Log.d(TAG, "unimplemented Method: endCurrentSession");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSessionManagerListener(ISessionManagerListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: addSessionManagerListener");
|
||||
this.sessionManagerListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSessionManagerListener(ISessionManagerListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: removeSessionManagerListener");
|
||||
this.sessionManagerListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addCastStateListener(ICastStateListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: addCastStateListener");
|
||||
this.castStateListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeCastStateListener(ICastStateListener listener) {
|
||||
Log.d(TAG, "unimplemented Method: removeCastStateListener");
|
||||
this.castStateListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IObjectWrapper getWrappedThis() throws RemoteException {
|
||||
return ObjectWrapper.wrap(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCastState() {
|
||||
return this.castState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void startSession(Bundle params) {
|
||||
Log.d(TAG, "unimplemented Method: startSession");
|
||||
String routeId = params.getString("CAST_INTENT_TO_CAST_ROUTE_ID_KEY");
|
||||
String sessionId = params.getString("CAST_INTENT_TO_CAST_SESSION_ID_KEY");
|
||||
}
|
||||
|
||||
public void onRouteSelected(String routeId, Bundle extras) {
|
||||
Log.d(TAG, "unimplemented Method: onRouteSelected: " + routeId);
|
||||
}
|
||||
|
||||
private void setCastState(int castState) {
|
||||
this.castState = castState;
|
||||
this.onCastStateChanged();
|
||||
}
|
||||
|
||||
public void onCastStateChanged() {
|
||||
for (ICastStateListener listener : this.castStateListeners) {
|
||||
try {
|
||||
listener.onCastStateChanged(this.castState);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onCastStateChanged: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionStarting(SessionImpl session) {
|
||||
this.setCastState(CastState.CONNECTING);
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionStarting(session.getSessionProxy().getWrappedSession());
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionStarting: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionStartFailed(SessionImpl session, int error) {
|
||||
this.currentSession = null;
|
||||
this.setCastState(CastState.NOT_CONNECTED);
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionStartFailed(session.getSessionProxy().getWrappedSession(), error);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionStartFailed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionStarted(SessionImpl session, String sessionId) {
|
||||
this.currentSession = session;
|
||||
this.setCastState(CastState.CONNECTED);
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionStarted(session.getSessionProxy().getWrappedSession(), sessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionStarted: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionResumed(SessionImpl session, boolean wasSuspended) {
|
||||
this.setCastState(CastState.CONNECTED);
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionResumed(session.getSessionProxy().getWrappedSession(), wasSuspended);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionResumed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionEnding(SessionImpl session) {
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionEnding(session.getSessionProxy().getWrappedSession());
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionEnding: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionEnded(SessionImpl session, int error) {
|
||||
this.currentSession = null;
|
||||
this.setCastState(CastState.NOT_CONNECTED);
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionEnded(session.getSessionProxy().getWrappedSession(), error);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionEnded: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionResuming(SessionImpl session, String sessionId) {
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionResuming(session.getSessionProxy().getWrappedSession(), sessionId);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionResuming: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionResumeFailed(SessionImpl session, int error) {
|
||||
this.currentSession = null;
|
||||
this.setCastState(CastState.NOT_CONNECTED);
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionResumeFailed(session.getSessionProxy().getWrappedSession(), error);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionResumeFailed: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onSessionSuspended(SessionImpl session, int reason) {
|
||||
this.setCastState(CastState.NOT_CONNECTED);
|
||||
for (ISessionManagerListener listener : this.sessionManagerListeners) {
|
||||
try {
|
||||
listener.onSessionSuspended(session.getSessionProxy().getWrappedSession(), reason);
|
||||
} catch (RemoteException e) {
|
||||
Log.d(TAG, "Remote exception calling onSessionSuspended: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.support.v7.media.MediaRouteProviderService;
|
||||
import android.support.v7.media.MediaRouteProvider;
|
||||
import android.util.Log;
|
||||
|
||||
public class CastMediaRouteProviderService extends MediaRouteProviderService {
|
||||
private static final String TAG = CastMediaRouteProviderService.class.getSimpleName();
|
||||
|
||||
@Override
|
||||
public MediaRouteProvider onCreateMediaRouteProvider() {
|
||||
return new CastMediaRouteProvider(this);
|
||||
}
|
||||
}
|
@ -179,7 +179,7 @@ public abstract class AbstractGmsServiceBroker extends IGmsServiceBroker.Stub {
|
||||
@Override
|
||||
public void getCastService(IGmsCallbacks callback, int versionCode, String packageName,
|
||||
IBinder binder, Bundle params) throws RemoteException {
|
||||
throw new IllegalArgumentException("Cast service not supported");
|
||||
callGetService(GmsService.CAST, callback, versionCode, packageName, params);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -0,0 +1,96 @@
|
||||
/*
|
||||
* 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.support.v7.media.MediaControlIntent;
|
||||
import android.support.v7.media.MediaRouteDescriptor;
|
||||
import android.support.v7.media.MediaRouteDiscoveryRequest;
|
||||
import android.support.v7.media.MediaRouteProvider;
|
||||
import android.support.v7.media.MediaRouteProviderDescriptor;
|
||||
import android.support.v7.media.MediaRouter;
|
||||
import android.util.Log;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -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.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.AsyncTask;
|
||||
import android.os.Handler;
|
||||
import android.support.v7.media.MediaControlIntent;
|
||||
import android.support.v7.media.MediaRouteDescriptor;
|
||||
import android.support.v7.media.MediaRouteDiscoveryRequest;
|
||||
import android.support.v7.media.MediaRouteProvider;
|
||||
import android.support.v7.media.MediaRouteProviderDescriptor;
|
||||
import android.support.v7.media.MediaRouter;
|
||||
import android.util.Log;
|
||||
|
||||
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",
|
||||
"<item>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.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());
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@
|
||||
-dontwarn org.oscim.tiling.source.OkHttpEngine$OkHttpFactory
|
||||
-dontwarn com.caverock.androidsvg.**
|
||||
-dontwarn org.slf4j.**
|
||||
-dontwarn org.codehaus.jackson.**
|
||||
|
||||
# Disable ProGuard Notes, they won't help here
|
||||
-dontnote
|
||||
@ -46,3 +47,8 @@
|
||||
-keep public class com.squareup.wire.Message
|
||||
-keep public class * extends com.squareup.wire.Message
|
||||
-keep public class * extends com.squareup.wire.Message$Builder { public <init>(...); }
|
||||
|
||||
# Proguard configuration for Jackson 1.x
|
||||
-keepclassmembers class * {
|
||||
@org.codehaus.jackson.annotate.* *;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user