Files
frameworks_base/services/java/com/android/server/media/RemoteDisplayProviderWatcher.java
Jeff Brown 69b07161be Add media router service and integrate with remote displays.
This change adds a new media router service whose purpose is to track
global state information associated with media routes.  This service
publishes routes to the media router instance in application processes
and handles requested state changes such as selecting or unselecting
global routes.  The service also binds to remote display provider
services which can offer new remote display routes to the system.

Includes a test application for manually verifying certain aspects
of the operation of the media router service.

The remote display provider interface is essentially a stripped down
media route provider interface as defined in the support library
media router implementation.  For now, it is designed to be used only
by first parties to publish remote display routes to the system so
it is not exposed as public API in the SDK.  In the future, the remote
display provider interface will most likely be deprecated and replaced
with a more featureful media route provider interface for third
party integration, similar to what is in the support library today.

Further patch sets integrate these new capabilities into the System UI
and Settings for connecting remote displays.

Bug: 11257292
Change-Id: I31109f23f17b474d17534d0f5f4503e388b081c2
2013-11-07 03:25:37 -08:00

182 lines
6.4 KiB
Java

/*
* Copyright (C) 2013 The Android Open Source Project
*
* 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.android.server.media;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.pm.ServiceInfo;
import android.media.RemoteDisplayState;
import android.os.Handler;
import android.os.UserHandle;
import android.util.Log;
import android.util.Slog;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Collections;
/**
* Watches for remote display provider services to be installed.
* Adds a provider to the media router for each registered service.
*
* @see RemoteDisplayProviderProxy
*/
public final class RemoteDisplayProviderWatcher {
private static final String TAG = "RemoteDisplayProvider"; // max. 23 chars
private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
private final Context mContext;
private final Callback mCallback;
private final Handler mHandler;
private final int mUserId;
private final PackageManager mPackageManager;
private final ArrayList<RemoteDisplayProviderProxy> mProviders =
new ArrayList<RemoteDisplayProviderProxy>();
private boolean mRunning;
public RemoteDisplayProviderWatcher(Context context,
Callback callback, Handler handler, int userId) {
mContext = context;
mCallback = callback;
mHandler = handler;
mUserId = userId;
mPackageManager = context.getPackageManager();
}
public void dump(PrintWriter pw, String prefix) {
pw.println(prefix + "Watcher");
pw.println(prefix + " mUserId=" + mUserId);
pw.println(prefix + " mRunning=" + mRunning);
pw.println(prefix + " mProviders.size()=" + mProviders.size());
}
public void start() {
if (!mRunning) {
mRunning = true;
IntentFilter filter = new IntentFilter();
filter.addAction(Intent.ACTION_PACKAGE_ADDED);
filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
filter.addDataScheme("package");
mContext.registerReceiverAsUser(mScanPackagesReceiver,
new UserHandle(mUserId), filter, null, mHandler);
// Scan packages.
// Also has the side-effect of restarting providers if needed.
mHandler.post(mScanPackagesRunnable);
}
}
public void stop() {
if (mRunning) {
mRunning = false;
mContext.unregisterReceiver(mScanPackagesReceiver);
mHandler.removeCallbacks(mScanPackagesRunnable);
// Stop all providers.
for (int i = mProviders.size() - 1; i >= 0; i--) {
mProviders.get(i).stop();
}
}
}
private void scanPackages() {
if (!mRunning) {
return;
}
// Add providers for all new services.
// Reorder the list so that providers left at the end will be the ones to remove.
int targetIndex = 0;
Intent intent = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
for (ResolveInfo resolveInfo : mPackageManager.queryIntentServicesAsUser(
intent, 0, mUserId)) {
ServiceInfo serviceInfo = resolveInfo.serviceInfo;
if (serviceInfo != null) {
int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
if (sourceIndex < 0) {
RemoteDisplayProviderProxy provider =
new RemoteDisplayProviderProxy(mContext,
new ComponentName(serviceInfo.packageName, serviceInfo.name),
mUserId);
provider.start();
mProviders.add(targetIndex++, provider);
mCallback.addProvider(provider);
} else if (sourceIndex >= targetIndex) {
RemoteDisplayProviderProxy provider = mProviders.get(sourceIndex);
provider.start(); // restart the provider if needed
provider.rebindIfDisconnected();
Collections.swap(mProviders, sourceIndex, targetIndex++);
}
}
}
// Remove providers for missing services.
if (targetIndex < mProviders.size()) {
for (int i = mProviders.size() - 1; i >= targetIndex; i--) {
RemoteDisplayProviderProxy provider = mProviders.get(i);
mCallback.removeProvider(provider);
mProviders.remove(provider);
provider.stop();
}
}
}
private int findProvider(String packageName, String className) {
int count = mProviders.size();
for (int i = 0; i < count; i++) {
RemoteDisplayProviderProxy provider = mProviders.get(i);
if (provider.hasComponentName(packageName, className)) {
return i;
}
}
return -1;
}
private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
if (DEBUG) {
Slog.d(TAG, "Received package manager broadcast: " + intent);
}
scanPackages();
}
};
private final Runnable mScanPackagesRunnable = new Runnable() {
@Override
public void run() {
scanPackages();
}
};
public interface Callback {
void addProvider(RemoteDisplayProviderProxy provider);
void removeProvider(RemoteDisplayProviderProxy provider);
}
}