1f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown/*
2f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * Copyright (C) 2013 The Android Open Source Project
3f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *
4f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * you may not use this file except in compliance with the License.
6f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * You may obtain a copy of the License at
7f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *
8f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *     http://www.apache.org/licenses/LICENSE-2.0
9f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *
10f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * Unless required by applicable law or agreed to in writing, software
11f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * See the License for the specific language governing permissions and
14f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * limitations under the License.
15f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown */
16f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
17f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownpackage com.android.media.remotedisplay;
18f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
1939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brownimport android.app.PendingIntent;
20f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.app.Service;
21f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.content.Context;
22f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.content.Intent;
23f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.media.IRemoteDisplayCallback;
24f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.media.IRemoteDisplayProvider;
25f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.media.RemoteDisplayState;
26f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.os.Handler;
27f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.os.IBinder;
28f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.os.Looper;
29f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.os.Message;
30f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.os.RemoteException;
3139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brownimport android.provider.Settings;
32f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport android.util.ArrayMap;
33f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
34f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownimport java.util.Collection;
35f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
36f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown/**
37f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * Base class for remote display providers implemented as unbundled services.
38f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * <p>
39f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * To implement your remote display provider service, create a subclass of
40f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * {@link Service} and override the {@link Service#onBind Service.onBind()} method
41f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * to return the provider's binder when the {@link #SERVICE_INTERFACE} is requested.
42f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * </p>
43f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * <pre>
44f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *   public class SampleRemoteDisplayProviderService extends Service {
45f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       private SampleProvider mProvider;
46f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *
47f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       public IBinder onBind(Intent intent) {
48f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           if (intent.getAction().equals(RemoteDisplayProvider.SERVICE_INTERFACE)) {
49f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               if (mProvider == null) {
50f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *                   mProvider = new SampleProvider(this);
51f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               }
52f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               return mProvider.getBinder();
53f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           }
54f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           return null;
55f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       }
56f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *
57f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       class SampleProvider extends RemoteDisplayProvider {
58f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           public SampleProvider() {
59f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               super(SampleRemoteDisplayProviderService.this);
60f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           }
61f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *
62f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           // --- Implementation goes here ---
63f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       }
64f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *   }
65f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * </pre>
66f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * <p>
67f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * Declare your remote display provider service in your application manifest
68f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * like this:
69f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * </p>
70f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * <pre>
71f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *   &lt;application>
72f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       &lt;uses-library android:name="com.android.media.remotedisplay" />
73f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *
74f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       &lt;service android:name=".SampleRemoteDisplayProviderService"
75f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               android:label="@string/sample_remote_display_provider_service"
76f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               android:exported="true"
77f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               android:permission="android.permission.BIND_REMOTE_DISPLAY">
78f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           &lt;intent-filter>
79f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *               &lt;action android:name="com.android.media.remotedisplay.RemoteDisplayProvider" />
80f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *           &lt;/intent-filter>
81f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *       &lt;/service>
82f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown *   &lt;/application>
83f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * </pre>
84f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * <p>
85f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * This object is not thread safe.  It is only intended to be accessed on the
86f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * {@link Context#getMainLooper main looper thread} of an application.
87f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * </p><p>
88f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * IMPORTANT: This class is effectively a public API for unbundled applications, and
89f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * must remain API stable. See README.txt in the root of this package for more information.
90f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown * </p>
91f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown */
92f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brownpublic abstract class RemoteDisplayProvider {
93f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private static final int MSG_SET_CALLBACK = 1;
94f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private static final int MSG_SET_DISCOVERY_MODE = 2;
95f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private static final int MSG_CONNECT = 3;
96f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private static final int MSG_DISCONNECT = 4;
97f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private static final int MSG_SET_VOLUME = 5;
98f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private static final int MSG_ADJUST_VOLUME = 6;
99f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
10039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    private final Context mContext;
101f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private final ProviderStub mStub;
102f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private final ProviderHandler mHandler;
103f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private final ArrayMap<String, RemoteDisplay> mDisplays =
104f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            new ArrayMap<String, RemoteDisplay>();
105f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private IRemoteDisplayCallback mCallback;
106f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    private int mDiscoveryMode = DISCOVERY_MODE_NONE;
107f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
10839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    private PendingIntent mSettingsPendingIntent;
10939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown
110f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
111f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * The {@link Intent} that must be declared as handled by the service.
112f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Put this in your manifest.
113f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
114f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public static final String SERVICE_INTERFACE = RemoteDisplayState.SERVICE_INTERFACE;
115f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
116f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
117f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Discovery mode: Do not perform any discovery.
118f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
119f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public static final int DISCOVERY_MODE_NONE = RemoteDisplayState.DISCOVERY_MODE_NONE;
120f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
121f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
122f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Discovery mode: Passive or low-power periodic discovery.
123f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * <p>
124f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * This mode indicates that an application is interested in knowing whether there
125f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * are any remote displays paired or available but doesn't need the latest or
126f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * most detailed information.  The provider may scan at a lower rate or rely on
127f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * knowledge of previously paired devices.
128f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * </p>
129f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
130f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public static final int DISCOVERY_MODE_PASSIVE = RemoteDisplayState.DISCOVERY_MODE_PASSIVE;
131f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
132f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
133f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Discovery mode: Active discovery.
134f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * <p>
135f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * This mode indicates that the user is actively trying to connect to a route
136f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * and we should perform continuous scans.  This mode may use significantly more
137f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * power but is intended to be short-lived.
138f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * </p>
139f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
140f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public static final int DISCOVERY_MODE_ACTIVE = RemoteDisplayState.DISCOVERY_MODE_ACTIVE;
141f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
142f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
143f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Creates a remote display provider.
144f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
145f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param context The application context for the remote display provider.
146f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
147f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public RemoteDisplayProvider(Context context) {
14839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown        mContext = context;
149f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        mStub = new ProviderStub();
150f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        mHandler = new ProviderHandler(context.getMainLooper());
151f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
152f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
153f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
15439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown     * Gets the context of the remote display provider.
15539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown     */
15639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    public final Context getContext() {
15739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown        return mContext;
15839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    }
15939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown
16039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    /**
161f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Gets the Binder associated with the provider.
162f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * <p>
163f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * This is intended to be used for the onBind() method of a service that implements
164f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * a remote display provider service.
165f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * </p>
166f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
167f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @return The IBinder instance associated with the provider.
168f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
169f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public IBinder getBinder() {
170f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        return mStub;
171f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
172f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
173f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
174f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Called when the current discovery mode changes.
175f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
176f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param mode The new discovery mode.
177f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
178f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void onDiscoveryModeChanged(int mode) {
179f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
180f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
181f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
182f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Called when the system would like to connect to a display.
183f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
184f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param display The remote display.
185f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
186f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void onConnect(RemoteDisplay display) {
187f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
188f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
189f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
190f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Called when the system would like to disconnect from a display.
191f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
192f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param display The remote display.
193f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
194f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void onDisconnect(RemoteDisplay display) {
195f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
196f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
197f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
198f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Called when the system would like to set the volume of a display.
199f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
200f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param display The remote display.
201f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param volume The desired volume.
202f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
203f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void onSetVolume(RemoteDisplay display, int volume) {
204f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
205f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
206f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
207f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Called when the system would like to adjust the volume of a display.
208f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
209f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param display The remote display.
210f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param delta An increment to add to the current volume, such as +1 or -1.
211f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
212f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void onAdjustVolume(RemoteDisplay display, int delta) {
213f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
214f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
215f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
216f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Gets the current discovery mode.
217f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
218f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @return The current discovery mode.
219f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
220f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public int getDiscoveryMode() {
221f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        return mDiscoveryMode;
222f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
223f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
224f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
225f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Gets the current collection of displays.
226f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
227f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @return The current collection of displays, which must not be modified.
228f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
229f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public Collection<RemoteDisplay> getDisplays() {
230f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        return mDisplays.values();
231f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
232f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
233f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
234f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Adds the specified remote display and notifies the system.
235f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
236f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param display The remote display that was added.
237f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @throws IllegalStateException if there is already a display with the same id.
238f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
239f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void addDisplay(RemoteDisplay display) {
240f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        if (display == null || mDisplays.containsKey(display.getId())) {
241f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            throw new IllegalArgumentException("display");
242f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
243f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        mDisplays.put(display.getId(), display);
244f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        publishState();
245f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
246f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
247f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
248f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Updates information about the specified remote display and notifies the system.
249f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
250f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param display The remote display that was added.
251f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @throws IllegalStateException if the display was n
252f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
253f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void updateDisplay(RemoteDisplay display) {
254f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        if (display == null || mDisplays.get(display.getId()) != display) {
255f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            throw new IllegalArgumentException("display");
256f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
257f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        publishState();
258f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
259f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
260f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    /**
261f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * Removes the specified remote display and tells the system about it.
262f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     *
263f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     * @param display The remote display that was removed.
264f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown     */
265f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    public void removeDisplay(RemoteDisplay display) {
266f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        if (display == null || mDisplays.get(display.getId()) != display) {
267f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            throw new IllegalArgumentException("display");
268f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
269f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        mDisplays.remove(display.getId());
270f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        publishState();
271f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
272f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
2735830b0b33618940d65197cec99d697b21908fec8Chong Zhang    /**
2745830b0b33618940d65197cec99d697b21908fec8Chong Zhang     * Finds the remote display with the specified id, returns null if not found.
2755830b0b33618940d65197cec99d697b21908fec8Chong Zhang     *
2765830b0b33618940d65197cec99d697b21908fec8Chong Zhang     * @param id Id of the remote display.
27739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown     * @return The display, or null if none.
2785830b0b33618940d65197cec99d697b21908fec8Chong Zhang     */
2795830b0b33618940d65197cec99d697b21908fec8Chong Zhang    public RemoteDisplay findRemoteDisplay(String id) {
2805830b0b33618940d65197cec99d697b21908fec8Chong Zhang        return mDisplays.get(id);
2815830b0b33618940d65197cec99d697b21908fec8Chong Zhang    }
2825830b0b33618940d65197cec99d697b21908fec8Chong Zhang
28339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    /**
28439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown     * Gets a pending intent to launch the remote display settings activity.
28539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown     *
28639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown     * @return A pending intent to launch the settings activity.
28739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown     */
28839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    public PendingIntent getSettingsPendingIntent() {
28939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown        if (mSettingsPendingIntent == null) {
29039ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown            Intent settingsIntent = new Intent(Settings.ACTION_WIFI_DISPLAY_SETTINGS);
29139ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown            settingsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
29239ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown                    | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED
29339ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown                    | Intent.FLAG_ACTIVITY_CLEAR_TOP);
29439ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown            mSettingsPendingIntent = PendingIntent.getActivity(
29539ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown                    mContext, 0, settingsIntent, 0, null);
29639ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown        }
29739ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown        return mSettingsPendingIntent;
29839ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown    }
29939ad0e559896b45185429ea17cd12f18f7ae842cJeff Brown
300f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    void setCallback(IRemoteDisplayCallback callback) {
301f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        mCallback = callback;
302f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        publishState();
303f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
304f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
305f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    void setDiscoveryMode(int mode) {
306f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        if (mDiscoveryMode != mode) {
307f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            mDiscoveryMode = mode;
308f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            onDiscoveryModeChanged(mode);
309f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
310f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
311f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
312f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    void publishState() {
313f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        if (mCallback != null) {
314f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            RemoteDisplayState state = new RemoteDisplayState();
315f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            final int count = mDisplays.size();
316f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            for (int i = 0; i < count; i++) {
317f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                final RemoteDisplay display = mDisplays.valueAt(i);
318f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                state.displays.add(display.getInfo());
319f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            }
320f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            try {
321f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                mCallback.onStateChanged(state);
322f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            } catch (RemoteException ex) {
323f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                // system server died?
324f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            }
325f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
326f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
327f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
328f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    final class ProviderStub extends IRemoteDisplayProvider.Stub {
329f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        @Override
330f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public void setCallback(IRemoteDisplayCallback callback) {
331f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            mHandler.obtainMessage(MSG_SET_CALLBACK, callback).sendToTarget();
332f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
333f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
334f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        @Override
335f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public void setDiscoveryMode(int mode) {
336f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            mHandler.obtainMessage(MSG_SET_DISCOVERY_MODE, mode, 0).sendToTarget();
337f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
338f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
339f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        @Override
340f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public void connect(String id) {
341f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            mHandler.obtainMessage(MSG_CONNECT, id).sendToTarget();
342f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
343f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
344f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        @Override
345f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public void disconnect(String id) {
346f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            mHandler.obtainMessage(MSG_DISCONNECT, id).sendToTarget();
347f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
348f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
349f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        @Override
350f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public void setVolume(String id, int volume) {
351f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            mHandler.obtainMessage(MSG_SET_VOLUME, volume, 0, id).sendToTarget();
352f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
353f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
354f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        @Override
355f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public void adjustVolume(String id, int delta) {
356f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            mHandler.obtainMessage(MSG_ADJUST_VOLUME, delta, 0, id).sendToTarget();
357f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
358f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
359f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
360f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    final class ProviderHandler extends Handler {
361f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public ProviderHandler(Looper looper) {
362f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            super(looper, null, true);
363f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
364f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown
365f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        @Override
366f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        public void handleMessage(Message msg) {
367f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            switch (msg.what) {
368f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                case MSG_SET_CALLBACK: {
369f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    setCallback((IRemoteDisplayCallback)msg.obj);
370f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    break;
371f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                }
372f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                case MSG_SET_DISCOVERY_MODE: {
373f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    setDiscoveryMode(msg.arg1);
374f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    break;
375f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                }
376f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                case MSG_CONNECT: {
377f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
378f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    if (display != null) {
379f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                        onConnect(display);
380f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    }
381f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    break;
382f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                }
383f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                case MSG_DISCONNECT: {
384f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
385f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    if (display != null) {
386f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                        onDisconnect(display);
387f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    }
388f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    break;
389f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                }
390f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                case MSG_SET_VOLUME: {
391f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
392f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    if (display != null) {
393f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                        onSetVolume(display, msg.arg1);
394f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    }
395f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    break;
396f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                }
397f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                case MSG_ADJUST_VOLUME: {
398f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    RemoteDisplay display = findRemoteDisplay((String)msg.obj);
399f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    if (display != null) {
400f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                        onAdjustVolume(display, msg.arg1);
401f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    }
402f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                    break;
403f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown                }
404f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown            }
405f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown        }
406f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown    }
407f3c99e883f46c56e5e2877e844b902b6eb45545bJeff Brown}
408