169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown/*
269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Copyright (C) 2013 The Android Open Source Project
369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown *
469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * you may not use this file except in compliance with the License.
669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * You may obtain a copy of the License at
769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown *
869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown *
1069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Unless required by applicable law or agreed to in writing, software
1169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
1269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * See the License for the specific language governing permissions and
1469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * limitations under the License.
1569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */
1669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
1769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownpackage com.android.server.media;
1869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
1969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.ComponentName;
2069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Context;
2169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.Intent;
2269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.content.ServiceConnection;
2369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.IRemoteDisplayCallback;
2469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.IRemoteDisplayProvider;
2569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.media.RemoteDisplayState;
2669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.Handler;
2769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.IBinder;
2869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.RemoteException;
2969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.IBinder.DeathRecipient;
3069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.os.UserHandle;
3169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Log;
3269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport android.util.Slog;
3369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
3469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.io.PrintWriter;
3569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownimport java.lang.ref.WeakReference;
36e6585b32ea586743258a5457e2184ffc087f2d2fKenny Rootimport java.util.Objects;
3769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
3869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown/**
3969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown * Maintains a connection to a particular remote display provider service.
4069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown */
4169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brownfinal class RemoteDisplayProviderProxy implements ServiceConnection {
4269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private static final String TAG = "RemoteDisplayProvider";  // max. 23 chars
4369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
4469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
4569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private final Context mContext;
4669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private final ComponentName mComponentName;
4769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private final int mUserId;
4869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private final Handler mHandler;
4969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
5069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private Callback mDisplayStateCallback;
5169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
5269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    // Connection state
5369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private boolean mRunning;
5469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private boolean mBound;
5569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private Connection mActiveConnection;
5669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private boolean mConnectionReady;
5769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
5869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    // Logical state
5969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private int mDiscoveryMode;
6069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private String mSelectedDisplayId;
6169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private RemoteDisplayState mDisplayState;
6269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private boolean mScheduledDisplayStateChangedCallback;
6369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
6469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public RemoteDisplayProviderProxy(Context context, ComponentName componentName,
6569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            int userId) {
6669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        mContext = context;
6769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        mComponentName = componentName;
6869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        mUserId = userId;
6969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        mHandler = new Handler();
7069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
7169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
7269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void dump(PrintWriter pw, String prefix) {
7369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "Proxy");
7469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mUserId=" + mUserId);
7569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mRunning=" + mRunning);
7669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mBound=" + mBound);
7769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mActiveConnection=" + mActiveConnection);
7869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mConnectionReady=" + mConnectionReady);
7969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mDiscoveryMode=" + mDiscoveryMode);
8069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mSelectedDisplayId=" + mSelectedDisplayId);
8169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        pw.println(prefix + "  mDisplayState=" + mDisplayState);
8269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
8369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
8469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void setCallback(Callback callback) {
8569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        mDisplayStateCallback = callback;
8669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
8769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
8869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public RemoteDisplayState getDisplayState() {
8969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        return mDisplayState;
9069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
9169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
9269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void setDiscoveryMode(int mode) {
9369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mDiscoveryMode != mode) {
9469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mDiscoveryMode = mode;
9569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mConnectionReady) {
9669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mActiveConnection.setDiscoveryMode(mode);
9769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
9869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            updateBinding();
9969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
10069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
10169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
10269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void setSelectedDisplay(String id) {
103e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root        if (!Objects.equals(mSelectedDisplayId, id)) {
10469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mConnectionReady && mSelectedDisplayId != null) {
10569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mActiveConnection.disconnect(mSelectedDisplayId);
10669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
10769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mSelectedDisplayId = id;
10869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mConnectionReady && id != null) {
10969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mActiveConnection.connect(id);
11069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
11169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            updateBinding();
11269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
11369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
11469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
11569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void setDisplayVolume(int volume) {
11669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mConnectionReady && mSelectedDisplayId != null) {
11769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mActiveConnection.setVolume(mSelectedDisplayId, volume);
11869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
11969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
12069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
12169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void adjustDisplayVolume(int delta) {
12269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mConnectionReady && mSelectedDisplayId != null) {
12369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mActiveConnection.adjustVolume(mSelectedDisplayId, delta);
12469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
12569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
12669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
12769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public boolean hasComponentName(String packageName, String className) {
12869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        return mComponentName.getPackageName().equals(packageName)
12969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                && mComponentName.getClassName().equals(className);
13069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
13169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
13269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public String getFlattenedComponentName() {
13369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        return mComponentName.flattenToShortString();
13469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
13569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
13669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void start() {
13769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (!mRunning) {
13869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (DEBUG) {
13969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.d(TAG, this + ": Starting");
14069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
14169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
14269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mRunning = true;
14369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            updateBinding();
14469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
14569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
14669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
14769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void stop() {
14869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mRunning) {
14969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (DEBUG) {
15069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.d(TAG, this + ": Stopping");
15169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
15269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
15369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mRunning = false;
15469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            updateBinding();
15569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
15669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
15769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
15869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void rebindIfDisconnected() {
15969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mActiveConnection == null && shouldBind()) {
16069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            unbind();
16169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            bind();
16269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
16369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
16469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
16569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void updateBinding() {
16669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (shouldBind()) {
16769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            bind();
16869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        } else {
16969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            unbind();
17069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
17169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
17269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
17369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private boolean shouldBind() {
17469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mRunning) {
17569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            // Bind whenever there is a discovery request or selected display.
17669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE
17769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    || mSelectedDisplayId != null) {
17869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                return true;
17969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
18069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
18169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        return false;
18269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
18369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
18469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void bind() {
18569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (!mBound) {
18669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (DEBUG) {
18769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.d(TAG, this + ": Binding");
18869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
18969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
19069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            Intent service = new Intent(RemoteDisplayState.SERVICE_INTERFACE);
19169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            service.setComponent(mComponentName);
19269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            try {
193d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn                mBound = mContext.bindServiceAsUser(service, this,
194d69e4c1460017062e7c36be55801cb434ad19d97Dianne Hackborn                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
19569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                        new UserHandle(mUserId));
19669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                if (!mBound && DEBUG) {
19769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    Slog.d(TAG, this + ": Bind failed");
19869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                }
19969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } catch (SecurityException ex) {
20069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                if (DEBUG) {
20169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    Slog.d(TAG, this + ": Bind failed", ex);
20269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                }
20369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
20469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
20569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
20669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
20769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void unbind() {
20869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mBound) {
20969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (DEBUG) {
21069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.d(TAG, this + ": Unbinding");
21169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
21269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
21369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mBound = false;
21469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            disconnect();
21569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mContext.unbindService(this);
21669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
21769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
21869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
21969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    @Override
22069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void onServiceConnected(ComponentName name, IBinder service) {
22169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (DEBUG) {
22269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            Slog.d(TAG, this + ": Connected");
22369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
22469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
22569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mBound) {
22669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            disconnect();
22769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
22869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            IRemoteDisplayProvider provider = IRemoteDisplayProvider.Stub.asInterface(service);
22969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (provider != null) {
23069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Connection connection = new Connection(provider);
23169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                if (connection.register()) {
23269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    mActiveConnection = connection;
23369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                } else {
23469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    if (DEBUG) {
23569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                        Slog.d(TAG, this + ": Registration failed");
23669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    }
23769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                }
23869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } else {
23969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.e(TAG, this + ": Service returned invalid remote display provider binder");
24069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
24169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
24269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
24369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
24469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    @Override
24569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public void onServiceDisconnected(ComponentName name) {
24669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (DEBUG) {
24769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            Slog.d(TAG, this + ": Service disconnected");
24869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
24969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        disconnect();
25069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
25169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
25269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void onConnectionReady(Connection connection) {
25369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mActiveConnection == connection) {
25469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mConnectionReady = true;
25569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
25669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mDiscoveryMode != RemoteDisplayState.DISCOVERY_MODE_NONE) {
25769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mActiveConnection.setDiscoveryMode(mDiscoveryMode);
25869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
25969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mSelectedDisplayId != null) {
26069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mActiveConnection.connect(mSelectedDisplayId);
26169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
26269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
26369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
26469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
26569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void onConnectionDied(Connection connection) {
26669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mActiveConnection == connection) {
26769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (DEBUG) {
26869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.d(TAG, this + ": Service connection died");
26969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
27069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            disconnect();
27169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
27269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
27369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
27469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void onDisplayStateChanged(Connection connection, RemoteDisplayState state) {
27569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mActiveConnection == connection) {
27669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (DEBUG) {
27769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.d(TAG, this + ": State changed, state=" + state);
27869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
27969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            setDisplayState(state);
28069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
28169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
28269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
28369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void disconnect() {
28469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        if (mActiveConnection != null) {
28569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mSelectedDisplayId != null) {
28669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mActiveConnection.disconnect(mSelectedDisplayId);
28769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
28869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mConnectionReady = false;
28969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mActiveConnection.dispose();
29069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mActiveConnection = null;
29169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            setDisplayState(null);
29269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
29369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
29469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
29569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private void setDisplayState(RemoteDisplayState state) {
296e6585b32ea586743258a5457e2184ffc087f2d2fKenny Root        if (!Objects.equals(mDisplayState, state)) {
29769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mDisplayState = state;
29869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (!mScheduledDisplayStateChangedCallback) {
29969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mScheduledDisplayStateChangedCallback = true;
30069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mHandler.post(mDisplayStateChanged);
30169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
30269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
30369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
30469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
30569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    @Override
30669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public String toString() {
30769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        return "Service connection " + mComponentName.flattenToShortString();
30869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
30969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
31069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private final Runnable mDisplayStateChanged = new Runnable() {
31169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        @Override
31269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void run() {
31369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mScheduledDisplayStateChangedCallback = false;
31469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (mDisplayStateCallback != null) {
31569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mDisplayStateCallback.onDisplayStateChanged(
31669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                        RemoteDisplayProviderProxy.this, mDisplayState);
31769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
31869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
31969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    };
32069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
32169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    public interface Callback {
32269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        void onDisplayStateChanged(RemoteDisplayProviderProxy provider, RemoteDisplayState state);
32369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
32469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
32569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private final class Connection implements DeathRecipient {
32669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        private final IRemoteDisplayProvider mProvider;
32769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        private final ProviderCallback mCallback;
32869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
32969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public Connection(IRemoteDisplayProvider provider) {
33069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mProvider = provider;
33169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mCallback = new ProviderCallback(this);
33269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
33369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
33469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public boolean register() {
33569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            try {
33669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mProvider.asBinder().linkToDeath(this, 0);
33769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mProvider.setCallback(mCallback);
33869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mHandler.post(new Runnable() {
33969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    @Override
34069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    public void run() {
34169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                        onConnectionReady(Connection.this);
34269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    }
34369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                });
34469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                return true;
34569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } catch (RemoteException ex) {
34669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                binderDied();
34769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
34869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            return false;
34969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
35069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
35169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void dispose() {
35269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mProvider.asBinder().unlinkToDeath(this, 0);
35369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mCallback.dispose();
35469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
35569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
35669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void setDiscoveryMode(int mode) {
35769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            try {
35869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mProvider.setDiscoveryMode(mode);
35969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } catch (RemoteException ex) {
36069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.e(TAG, "Failed to deliver request to set discovery mode.", ex);
36169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
36269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
36369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
36469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void connect(String id) {
36569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            try {
36669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mProvider.connect(id);
36769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } catch (RemoteException ex) {
36869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.e(TAG, "Failed to deliver request to connect to display.", ex);
36969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
37069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
37169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
37269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void disconnect(String id) {
37369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            try {
37469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mProvider.disconnect(id);
37569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } catch (RemoteException ex) {
37669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.e(TAG, "Failed to deliver request to disconnect from display.", ex);
37769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
37869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
37969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
38069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void setVolume(String id, int volume) {
38169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            try {
38269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mProvider.setVolume(id, volume);
38369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } catch (RemoteException ex) {
38469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.e(TAG, "Failed to deliver request to set display volume.", ex);
38569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
38669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
38769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
38869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void adjustVolume(String id, int volume) {
38969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            try {
39069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                mProvider.adjustVolume(id, volume);
39169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            } catch (RemoteException ex) {
39269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                Slog.e(TAG, "Failed to deliver request to adjust display volume.", ex);
39369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
39469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
39569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
39669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        @Override
39769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void binderDied() {
39869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mHandler.post(new Runnable() {
39969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                @Override
40069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                public void run() {
40169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    onConnectionDied(Connection.this);
40269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                }
40369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            });
40469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
40569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
40669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        void postStateChanged(final RemoteDisplayState state) {
40769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mHandler.post(new Runnable() {
40869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                @Override
40969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                public void run() {
41069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                    onDisplayStateChanged(Connection.this, state);
41169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                }
41269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            });
41369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
41469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
41569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
41669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    /**
41769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown     * Receives callbacks from the service.
41869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown     * <p>
41969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown     * This inner class is static and only retains a weak reference to the connection
42069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown     * to prevent the client from being leaked in case the service is holding an
42169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown     * active reference to the client's callback.
42269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown     * </p>
42369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown     */
42469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    private static final class ProviderCallback extends IRemoteDisplayCallback.Stub {
42569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        private final WeakReference<Connection> mConnectionRef;
42669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
42769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public ProviderCallback(Connection connection) {
42869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mConnectionRef = new WeakReference<Connection>(connection);
42969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
43069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
43169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void dispose() {
43269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            mConnectionRef.clear();
43369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
43469b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown
43569b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        @Override
43669b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        public void onStateChanged(RemoteDisplayState state) throws RemoteException {
43769b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            Connection connection = mConnectionRef.get();
43869b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            if (connection != null) {
43969b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown                connection.postStateChanged(state);
44069b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown            }
44169b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown        }
44269b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown    }
44369b07161bebdb2c726e3a826c2268866f1a94517Jeff Brown}
444