• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.android.server.media;
18 
19 import android.annotation.NonNull;
20 import android.annotation.Nullable;
21 import android.content.ComponentName;
22 import android.media.MediaRoute2Info;
23 import android.media.MediaRoute2ProviderInfo;
24 import android.media.MediaRouter2;
25 import android.media.MediaRouter2Utils;
26 import android.media.RouteDiscoveryPreference;
27 import android.media.RoutingSessionInfo;
28 import android.os.Bundle;
29 import android.os.UserHandle;
30 
31 import com.android.internal.annotations.GuardedBy;
32 
33 import java.io.PrintWriter;
34 import java.util.ArrayList;
35 import java.util.List;
36 import java.util.Objects;
37 import java.util.Set;
38 
39 abstract class MediaRoute2Provider {
40     final ComponentName mComponentName;
41     final String mUniqueId;
42     final Object mLock = new Object();
43 
44     Callback mCallback;
45     boolean mIsSystemRouteProvider;
46     private volatile MediaRoute2ProviderInfo mProviderInfo;
47 
48     @GuardedBy("mLock")
49     final List<RoutingSessionInfo> mSessionInfos = new ArrayList<>();
50 
MediaRoute2Provider(@onNull ComponentName componentName)51     MediaRoute2Provider(@NonNull ComponentName componentName) {
52         mComponentName = Objects.requireNonNull(componentName, "Component name must not be null.");
53         mUniqueId = componentName.flattenToShortString();
54     }
55 
setCallback(Callback callback)56     public void setCallback(Callback callback) {
57         mCallback = callback;
58     }
59 
requestCreateSession( long requestId, String packageName, String routeOriginalId, @Nullable Bundle sessionHints, @RoutingSessionInfo.TransferReason int transferReason, @NonNull UserHandle transferInitiatorUserHandle, @NonNull String transferInitiatorPackageName)60     public abstract void requestCreateSession(
61             long requestId,
62             String packageName,
63             String routeOriginalId,
64             @Nullable Bundle sessionHints,
65             @RoutingSessionInfo.TransferReason int transferReason,
66             @NonNull UserHandle transferInitiatorUserHandle,
67             @NonNull String transferInitiatorPackageName);
68 
releaseSession(long requestId, String sessionId)69     public abstract void releaseSession(long requestId, String sessionId);
70 
updateDiscoveryPreference( Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference)71     public abstract void updateDiscoveryPreference(
72             Set<String> activelyScanningPackages, RouteDiscoveryPreference discoveryPreference);
73 
selectRoute(long requestId, String sessionId, String routeId)74     public abstract void selectRoute(long requestId, String sessionId, String routeId);
deselectRoute(long requestId, String sessionId, String routeId)75     public abstract void deselectRoute(long requestId, String sessionId, String routeId);
76 
transferToRoute( long requestId, @NonNull UserHandle transferInitiatorUserHandle, @NonNull String transferInitiatorPackageName, String sessionOriginalId, String routeOriginalId, @RoutingSessionInfo.TransferReason int transferReason)77     public abstract void transferToRoute(
78             long requestId,
79             @NonNull UserHandle transferInitiatorUserHandle,
80             @NonNull String transferInitiatorPackageName,
81             String sessionOriginalId,
82             String routeOriginalId,
83             @RoutingSessionInfo.TransferReason int transferReason);
84 
setRouteVolume(long requestId, String routeOriginalId, int volume)85     public abstract void setRouteVolume(long requestId, String routeOriginalId, int volume);
86 
setSessionVolume(long requestId, String sessionOriginalId, int volume)87     public abstract void setSessionVolume(long requestId, String sessionOriginalId, int volume);
88 
prepareReleaseSession(@onNull String sessionUniqueId)89     public abstract void prepareReleaseSession(@NonNull String sessionUniqueId);
90 
91     @NonNull
getUniqueId()92     public String getUniqueId() {
93         return mUniqueId;
94     }
95 
96     @Nullable
getProviderInfo()97     public MediaRoute2ProviderInfo getProviderInfo() {
98         return mProviderInfo;
99     }
100 
101     @NonNull
getSessionInfos()102     public List<RoutingSessionInfo> getSessionInfos() {
103         synchronized (mLock) {
104             return new ArrayList<>(mSessionInfos);
105         }
106     }
107 
setProviderState(MediaRoute2ProviderInfo providerInfo)108     void setProviderState(MediaRoute2ProviderInfo providerInfo) {
109         if (providerInfo == null) {
110             mProviderInfo = null;
111         } else {
112             mProviderInfo = new MediaRoute2ProviderInfo.Builder(providerInfo)
113                     .setUniqueId(mComponentName.getPackageName(), mUniqueId)
114                     .setSystemRouteProvider(mIsSystemRouteProvider)
115                     .build();
116         }
117     }
118 
notifyProviderState()119     void notifyProviderState() {
120         if (mCallback != null) {
121             mCallback.onProviderStateChanged(this);
122         }
123     }
124 
setAndNotifyProviderState(MediaRoute2ProviderInfo providerInfo)125     void setAndNotifyProviderState(MediaRoute2ProviderInfo providerInfo) {
126         setProviderState(providerInfo);
127         notifyProviderState();
128     }
129 
hasComponentName(String packageName, String className)130     public boolean hasComponentName(String packageName, String className) {
131         return mComponentName.getPackageName().equals(packageName)
132                 && mComponentName.getClassName().equals(className);
133     }
134 
dump(PrintWriter pw, String prefix)135     public void dump(PrintWriter pw, String prefix) {
136         pw.println(prefix + getDebugString());
137         prefix += "  ";
138 
139         if (mProviderInfo == null) {
140             pw.println(prefix + "<provider info not received, yet>");
141         } else if (mProviderInfo.getRoutes().isEmpty()) {
142             pw.println(prefix + "<provider info has no routes>");
143         } else {
144             for (MediaRoute2Info route : mProviderInfo.getRoutes()) {
145                 pw.printf("%s%s | %s\n", prefix, route.getId(), route.getName());
146             }
147         }
148 
149         pw.println(prefix + "Active routing sessions:");
150         synchronized (mLock) {
151             if (mSessionInfos.isEmpty()) {
152                 pw.println(prefix + "  <no active routing sessions>");
153             } else {
154                 for (RoutingSessionInfo routingSessionInfo : mSessionInfos) {
155                     routingSessionInfo.dump(pw, prefix + "  ");
156                 }
157             }
158         }
159     }
160 
161     @Override
toString()162     public String toString() {
163         return getDebugString();
164     }
165 
166     /** Returns a human-readable string describing the instance, for debugging purposes. */
getDebugString()167     protected abstract String getDebugString();
168 
169     public interface Callback {
onProviderStateChanged(@ullable MediaRoute2Provider provider)170         void onProviderStateChanged(@Nullable MediaRoute2Provider provider);
onSessionCreated(@onNull MediaRoute2Provider provider, long requestId, @Nullable RoutingSessionInfo sessionInfo)171         void onSessionCreated(@NonNull MediaRoute2Provider provider,
172                 long requestId, @Nullable RoutingSessionInfo sessionInfo);
onSessionUpdated(@onNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo)173         void onSessionUpdated(@NonNull MediaRoute2Provider provider,
174                 @NonNull RoutingSessionInfo sessionInfo);
onSessionReleased(@onNull MediaRoute2Provider provider, @NonNull RoutingSessionInfo sessionInfo)175         void onSessionReleased(@NonNull MediaRoute2Provider provider,
176                 @NonNull RoutingSessionInfo sessionInfo);
onRequestFailed(@onNull MediaRoute2Provider provider, long requestId, int reason)177         void onRequestFailed(@NonNull MediaRoute2Provider provider, long requestId, int reason);
178     }
179 
180     /**
181      * Holds session creation or transfer initiation information for a transfer in flight.
182      *
183      * <p>The initiator app is typically also the {@link RoutingSessionInfo#getClientPackageName()
184      * client app}, with the exception of the {@link MediaRouter2#getSystemController() system
185      * routing session} which is exceptional in that it's shared among all apps.
186      *
187      * <p>For the system routing session, the initiator app is the one that programmatically
188      * triggered the transfer (for example, via {@link MediaRouter2#transferTo}), or the target app
189      * of the proxy router that did the transfer.
190      *
191      * @see MediaRouter2.RoutingController#wasTransferInitiatedBySelf()
192      * @see RoutingSessionInfo#getTransferInitiatorPackageName()
193      * @see RoutingSessionInfo#getTransferInitiatorUserHandle()
194      */
195     protected static class SessionCreationOrTransferRequest {
196 
197         /**
198          * The id of the request, or {@link
199          * android.media.MediaRoute2ProviderService#REQUEST_ID_NONE} if unknown.
200          */
201         public final long mRequestId;
202 
203         /** The {@link MediaRoute2Info#getOriginalId()} original id} of the target route. */
204         @NonNull public final String mTargetOriginalRouteId;
205 
206         @RoutingSessionInfo.TransferReason public final int mTransferReason;
207 
208         /** The {@link android.os.UserHandle} on which the initiator app is running. */
209         @NonNull public final UserHandle mTransferInitiatorUserHandle;
210 
211         @NonNull public final String mTransferInitiatorPackageName;
212 
SessionCreationOrTransferRequest( long requestId, @NonNull String targetOriginalRouteId, @RoutingSessionInfo.TransferReason int transferReason, @NonNull UserHandle transferInitiatorUserHandle, @NonNull String transferInitiatorPackageName)213         SessionCreationOrTransferRequest(
214                 long requestId,
215                 @NonNull String targetOriginalRouteId,
216                 @RoutingSessionInfo.TransferReason int transferReason,
217                 @NonNull UserHandle transferInitiatorUserHandle,
218                 @NonNull String transferInitiatorPackageName) {
219             mRequestId = requestId;
220             mTargetOriginalRouteId = targetOriginalRouteId;
221             mTransferReason = transferReason;
222             mTransferInitiatorUserHandle = transferInitiatorUserHandle;
223             mTransferInitiatorPackageName = transferInitiatorPackageName;
224         }
225 
isTargetRoute(@ullable MediaRoute2Info route2Info)226         public boolean isTargetRoute(@Nullable MediaRoute2Info route2Info) {
227             return route2Info != null && mTargetOriginalRouteId.equals(route2Info.getOriginalId());
228         }
229 
230         /**
231          * Returns whether the given list of {@link MediaRoute2Info#getOriginalId() original ids}
232          * contains the {@link #mTargetOriginalRouteId target route id}.
233          */
isTargetRouteIdInRouteOriginalIdList( @onNull List<String> originalRouteIdList)234         public boolean isTargetRouteIdInRouteOriginalIdList(
235                 @NonNull List<String> originalRouteIdList) {
236             return originalRouteIdList.stream().anyMatch(mTargetOriginalRouteId::equals);
237         }
238 
239         /**
240          * Returns whether the given list of {@link MediaRoute2Info#getId() unique ids} contains the
241          * {@link #mTargetOriginalRouteId target route id}.
242          */
isTargetRouteIdInRouteUniqueIdList(@onNull List<String> uniqueRouteIdList)243         public boolean isTargetRouteIdInRouteUniqueIdList(@NonNull List<String> uniqueRouteIdList) {
244             return uniqueRouteIdList.stream()
245                     .map(MediaRouter2Utils::getOriginalId)
246                     .anyMatch(mTargetOriginalRouteId::equals);
247         }
248     }
249 }
250