Merge "QS: Wire up screen casting to tile/panel." into lmp-dev
diff --git a/media/java/android/media/projection/MediaProjectionInfo.java b/media/java/android/media/projection/MediaProjectionInfo.java
index 7ebc31f..5a65e65 100644
--- a/media/java/android/media/projection/MediaProjectionInfo.java
+++ b/media/java/android/media/projection/MediaProjectionInfo.java
@@ -20,6 +20,8 @@
import android.os.Parcelable;
import android.os.UserHandle;
+import java.util.Objects;
+
/** @hide */
public final class MediaProjectionInfo implements Parcelable {
private final String mPackageName;
@@ -44,6 +46,21 @@
}
@Override
+ public boolean equals(Object o) {
+ if (o instanceof MediaProjectionInfo) {
+ final MediaProjectionInfo other = (MediaProjectionInfo) o;
+ return Objects.equals(other.mPackageName, mPackageName)
+ && Objects.equals(other.mUserHandle, mUserHandle);
+ }
+ return false;
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(mPackageName, mUserHandle);
+ }
+
+ @Override
public String toString() {
return "MediaProjectionInfo{mPackageName="
+ mPackageName + ", mUserHandle="
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
index 6cd0f39..f503657 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CastTile.java
@@ -239,7 +239,8 @@
@Override
public void onDetailItemDisconnect(Item item) {
if (item == null || item.tag == null) return;
- mController.stopCasting();
+ final CastDevice device = (CastDevice) item.tag;
+ mController.stopCasting(device);
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
index eb5804a..7713e57 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastController.java
@@ -25,7 +25,7 @@
void setCurrentUserId(int currentUserId);
Set<CastDevice> getCastDevices();
void startCasting(CastDevice device);
- void stopCasting();
+ void stopCasting(CastDevice device);
public interface Callback {
void onCastDevicesChanged();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
index 22179e0..eb0be05 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/CastControllerImpl.java
@@ -19,15 +19,25 @@
import static android.media.MediaRouter.ROUTE_TYPE_REMOTE_DISPLAY;
import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.pm.PackageManager.NameNotFoundException;
import android.media.MediaRouter;
import android.media.MediaRouter.RouteInfo;
+import android.media.projection.MediaProjectionInfo;
+import android.media.projection.MediaProjectionManager;
+import android.os.Handler;
+import android.text.TextUtils;
import android.util.ArrayMap;
import android.util.ArraySet;
import android.util.Log;
+import com.android.systemui.R;
+
import java.io.FileDescriptor;
import java.io.PrintWriter;
import java.util.ArrayList;
+import java.util.Objects;
import java.util.Set;
import java.util.UUID;
@@ -41,12 +51,19 @@
private final MediaRouter mMediaRouter;
private final ArrayMap<String, RouteInfo> mRoutes = new ArrayMap<>();
private final Object mDiscoveringLock = new Object();
+ private final MediaProjectionManager mProjectionManager;
+ private final Object mProjectionLock = new Object();
private boolean mDiscovering;
+ private MediaProjectionInfo mProjection;
public CastControllerImpl(Context context) {
mContext = context;
mMediaRouter = (MediaRouter) context.getSystemService(Context.MEDIA_ROUTER_SERVICE);
+ mProjectionManager = (MediaProjectionManager)
+ context.getSystemService(Context.MEDIA_PROJECTION_SERVICE);
+ mProjection = mProjectionManager.getActiveProjectionInfo();
+ mProjectionManager.addCallback(mProjectionCallback, new Handler());
if (DEBUG) Log.d(TAG, "new CastController()");
}
@@ -59,6 +76,7 @@
final RouteInfo route = mRoutes.valueAt(i);
pw.print(" "); pw.println(routeToString(route));
}
+ pw.print(" mProjection="); pw.println(mProjection);
}
@Override
@@ -95,6 +113,18 @@
@Override
public Set<CastDevice> getCastDevices() {
final ArraySet<CastDevice> devices = new ArraySet<CastDevice>();
+ synchronized (mProjectionLock) {
+ if (mProjection != null) {
+ final CastDevice device = new CastDevice();
+ device.id = mProjection.getPackageName();
+ device.name = getAppName(mProjection.getPackageName());
+ device.description = mContext.getString(R.string.quick_settings_casting);
+ device.state = CastDevice.STATE_CONNECTED;
+ device.tag = mProjection;
+ devices.add(device);
+ return devices;
+ }
+ }
synchronized(mRoutes) {
for (RouteInfo route : mRoutes.values()) {
final CastDevice device = new CastDevice();
@@ -122,9 +152,55 @@
}
@Override
- public void stopCasting() {
- if (DEBUG) Log.d(TAG, "stopCasting");
- mMediaRouter.getDefaultRoute().select();
+ public void stopCasting(CastDevice device) {
+ final boolean isProjection = device.tag instanceof MediaProjectionInfo;
+ if (DEBUG) Log.d(TAG, "stopCasting isProjection=" + isProjection);
+ if (isProjection) {
+ final MediaProjectionInfo projection = (MediaProjectionInfo) device.tag;
+ if (Objects.equals(mProjectionManager.getActiveProjectionInfo(), projection)) {
+ mProjectionManager.stopActiveProjection();
+ } else {
+ Log.w(TAG, "Projection is no longer active: " + projection);
+ }
+ } else {
+ mMediaRouter.getDefaultRoute().select();
+ }
+ }
+
+ private void setProjection(MediaProjectionInfo projection, boolean started) {
+ boolean changed = false;
+ final MediaProjectionInfo oldProjection = mProjection;
+ synchronized (mProjectionLock) {
+ final boolean isCurrent = Objects.equals(projection, mProjection);
+ if (started && !isCurrent) {
+ mProjection = projection;
+ changed = true;
+ } else if (!started && isCurrent) {
+ mProjection = null;
+ changed = true;
+ }
+ }
+ if (changed) {
+ if (DEBUG) Log.d(TAG, "setProjection: " + oldProjection + " -> " + mProjection);
+ fireOnCastDevicesChanged();
+ }
+ }
+
+ private String getAppName(String packageName) {
+ final PackageManager pm = mContext.getPackageManager();
+ try {
+ final ApplicationInfo appInfo = pm.getApplicationInfo(packageName, 0);
+ if (appInfo != null) {
+ final CharSequence label = appInfo.loadLabel(pm);
+ if (!TextUtils.isEmpty(label)) {
+ return label.toString();
+ }
+ }
+ Log.w(TAG, "No label found for package: " + packageName);
+ } catch (NameNotFoundException e) {
+ Log.w(TAG, "Error getting appName for package: " + packageName, e);
+ }
+ return packageName;
}
private void updateRemoteDisplays() {
@@ -202,4 +278,17 @@
updateRemoteDisplays();
}
};
+
+ private final MediaProjectionManager.Callback mProjectionCallback
+ = new MediaProjectionManager.Callback() {
+ @Override
+ public void onStart(MediaProjectionInfo info) {
+ setProjection(info, true);
+ }
+
+ @Override
+ public void onStop(MediaProjectionInfo info) {
+ setProjection(info, false);
+ }
+ };
}
diff --git a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
index 69d1dc9..8ec9b254 100644
--- a/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
+++ b/services/core/java/com/android/server/media/projection/MediaProjectionManagerService.java
@@ -111,7 +111,6 @@
@Override
public void binderDied() {
synchronized (mLock) {
- unlinkDeathRecipientLocked(callback);
removeCallback(callback);
}
}
@@ -125,7 +124,7 @@
private void removeCallback(IMediaProjectionWatcherCallback callback) {
synchronized (mLock) {
unlinkDeathRecipientLocked(callback);
- removeCallback(callback);
+ mCallbackDelegate.remove(callback);
}
}