diff options
author | John Spurlock <jspurlock@google.com> | 2014-08-25 17:52:06 -0400 |
---|---|---|
committer | John Spurlock <jspurlock@google.com> | 2014-08-25 17:55:08 -0400 |
commit | 78b8c8fbde12b214314cc2ab2644350b5d5189a5 (patch) | |
tree | 0b232017fed212e835e2906dc32201e99cc8cdb2 /packages | |
parent | 6adf1588fd2bccb8cf95a9c3456230bba805fab9 (diff) | |
download | frameworks_base-78b8c8fbde12b214314cc2ab2644350b5d5189a5.zip frameworks_base-78b8c8fbde12b214314cc2ab2644350b5d5189a5.tar.gz frameworks_base-78b8c8fbde12b214314cc2ab2644350b5d5189a5.tar.bz2 |
QS: Wire up screen casting to tile/panel.
Use MediaProjectionManager to determine whether or not
screencasting is active, when it changes, and to stop
casting.
Also:
- Implement hashCode/equals on MediaProjectionInfo
- Fix unintentional recursion in the service.
Bug:16488053
Change-Id: Icd1a88f23bbdf1d4c1915b30cb2508f8fe9d6d7e
Diffstat (limited to 'packages')
3 files changed, 95 insertions, 5 deletions
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 @@ public class CastTile extends QSTile<QSTile.BooleanState> { @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 @@ public interface CastController { 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 @@ package com.android.systemui.statusbar.policy; 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 @@ public class CastControllerImpl implements CastController { 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 @@ public class CastControllerImpl implements CastController { final RouteInfo route = mRoutes.valueAt(i); pw.print(" "); pw.println(routeToString(route)); } + pw.print(" mProjection="); pw.println(mProjection); } @Override @@ -95,6 +113,18 @@ public class CastControllerImpl implements CastController { @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 @@ public class CastControllerImpl implements CastController { } @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 @@ public class CastControllerImpl implements CastController { 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); + } + }; } |