RegisteredMediaRouteProviderWatcher.java revision b507e525a61ed761eecfc2eaaf19af7e8db5dca5
1fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/*
2fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Copyright (C) 2013 The Android Open Source Project
3fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *
4fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Licensed under the Apache License, Version 2.0 (the "License");
5fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * you may not use this file except in compliance with the License.
6fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * You may obtain a copy of the License at
7fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *
8fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *      http://www.apache.org/licenses/LICENSE-2.0
9fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *
10fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Unless required by applicable law or agreed to in writing, software
11fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * distributed under the License is distributed on an "AS IS" BASIS,
12fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * See the License for the specific language governing permissions and
14fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * limitations under the License.
15fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */
16fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
17b507e525a61ed761eecfc2eaaf19af7e8db5dca5Jeff Brownpackage android.support.v7.media;
18fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
19fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.BroadcastReceiver;
20fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.ComponentName;
21fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.Context;
22fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.Intent;
23fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.IntentFilter;
24fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.pm.PackageManager;
25fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.pm.ResolveInfo;
26fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport android.content.pm.ServiceInfo;
27fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
28fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.util.ArrayList;
29fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.util.Collections;
30fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
31fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/**
32fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Watches for media route provider services to be installed.
33fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Adds a provider to the media router for each registered service.
34fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown *
35fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see RegisteredMediaRouteProvider
36fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */
37fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownfinal class RegisteredMediaRouteProviderWatcher {
38fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final Context mContext;
39fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final MediaRouter mRouter;
40fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final ArrayList<RegisteredMediaRouteProvider> mProviders =
41fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            new ArrayList<RegisteredMediaRouteProvider>();
42fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private final PackageManager mPackageManager;
43fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
44fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public RegisteredMediaRouteProviderWatcher(Context context, MediaRouter router) {
45fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mContext = context;
46fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mRouter = router;
47fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mPackageManager = context.getPackageManager();
48fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
50fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    public void start() {
51fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        IntentFilter filter = new IntentFilter();
52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        filter.addAction(Intent.ACTION_PACKAGE_ADDED);
53fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        mContext.registerReceiver(new BroadcastReceiver() {
56fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            @Override
57fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            public void onReceive(Context context, Intent intent) {
58fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                scanPackages();
59fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
60fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }, filter);
61fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
62fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        scanPackages();
63fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
64fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
65fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private void scanPackages() {
66fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        // Add providers for all new services.
67fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        // Reorder the list so that providers left at the end will be the ones to remove.
68fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int targetIndex = 0;
69fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        Intent intent = new Intent(MediaRouteProviderService.SERVICE_INTERFACE);
70fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        for (ResolveInfo resolveInfo : mPackageManager.queryIntentServices(intent, 0)) {
71fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            ServiceInfo serviceInfo = resolveInfo.serviceInfo;
72fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (serviceInfo != null) {
73fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
74fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                if (sourceIndex < 0) {
75fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    RegisteredMediaRouteProvider provider =
76fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            new RegisteredMediaRouteProvider(mContext,
77fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                            new ComponentName(serviceInfo.packageName, serviceInfo.name));
78fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    provider.bind();
79fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    mProviders.add(targetIndex++, provider);
80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    mRouter.addProvider(provider);
81fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                } else if (sourceIndex >= targetIndex) {
82fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    RegisteredMediaRouteProvider provider = mProviders.get(sourceIndex);
83fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    provider.rebindIfDisconnected();
84fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                    Collections.swap(mProviders, sourceIndex, targetIndex++);
85fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                }
86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
87fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
89fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        // Remove providers for missing services.
90fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        if (targetIndex < mProviders.size()) {
91fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            for (int i = mProviders.size() - 1; i >= targetIndex; i--) {
92fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                RegisteredMediaRouteProvider provider = mProviders.get(i);
93fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mRouter.removeProvider(provider);
94fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                mProviders.remove(provider);
95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                provider.unbind();
96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
97fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
98fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
99fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown
100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    private int findProvider(String packageName, String className) {
101fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        int count = mProviders.size();
102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        for (int i = 0; i < count; i++) {
103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            RegisteredMediaRouteProvider provider = mProviders.get(i);
104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            if (provider.hasComponentName(packageName, className)) {
105fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown                return i;
106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown            }
107fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        }
108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown        return -1;
109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown    }
110fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown}
111