RegisteredMediaRouteProviderWatcher.java revision adf0f4a217e14894af07dfa9f46cad7d98b8a7f4
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; 273efa63d3b896244713e84acbb5945562dce41d77Jeff Brownimport android.os.Handler; 28fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 29fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.util.ArrayList; 30fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownimport java.util.Collections; 31fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 32fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown/** 33fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Watches for media route provider services to be installed. 34fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * Adds a provider to the media router for each registered service. 35fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * 36fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown * @see RegisteredMediaRouteProvider 37fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown */ 38fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brownfinal class RegisteredMediaRouteProviderWatcher { 39fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final Context mContext; 403efa63d3b896244713e84acbb5945562dce41d77Jeff Brown private final Callback mCallback; 413efa63d3b896244713e84acbb5945562dce41d77Jeff Brown private final Handler mHandler; 423efa63d3b896244713e84acbb5945562dce41d77Jeff Brown private final PackageManager mPackageManager; 433efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 44fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private final ArrayList<RegisteredMediaRouteProvider> mProviders = 45fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new ArrayList<RegisteredMediaRouteProvider>(); 463efa63d3b896244713e84acbb5945562dce41d77Jeff Brown private boolean mRunning; 47fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 483efa63d3b896244713e84acbb5945562dce41d77Jeff Brown public RegisteredMediaRouteProviderWatcher(Context context, Callback callback) { 49fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mContext = context; 503efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mCallback = callback; 513efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mHandler = new Handler(); 52fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mPackageManager = context.getPackageManager(); 53fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 54fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 55fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown public void start() { 563efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (!mRunning) { 573efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mRunning = true; 583efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 593efa63d3b896244713e84acbb5945562dce41d77Jeff Brown IntentFilter filter = new IntentFilter(); 603efa63d3b896244713e84acbb5945562dce41d77Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_ADDED); 613efa63d3b896244713e84acbb5945562dce41d77Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_REMOVED); 623efa63d3b896244713e84acbb5945562dce41d77Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_CHANGED); 63adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_REPLACED); 64adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown filter.addAction(Intent.ACTION_PACKAGE_RESTARTED); 65adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown filter.addDataScheme("package"); 66adf0f4a217e14894af07dfa9f46cad7d98b8a7f4Jeff Brown mContext.registerReceiver(mScanPackagesReceiver, filter, null, mHandler); 673efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 683efa63d3b896244713e84acbb5945562dce41d77Jeff Brown // Scan packages. 693efa63d3b896244713e84acbb5945562dce41d77Jeff Brown // Also has the side-effect of restarting providers if needed. 703efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mHandler.post(mScanPackagesRunnable); 713efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 723efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 733efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 743efa63d3b896244713e84acbb5945562dce41d77Jeff Brown public void stop() { 753efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (mRunning) { 763efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mRunning = false; 773efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 783efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mContext.unregisterReceiver(mScanPackagesReceiver); 793efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mHandler.removeCallbacks(mScanPackagesRunnable); 80fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 813efa63d3b896244713e84acbb5945562dce41d77Jeff Brown // Stop all providers. 823efa63d3b896244713e84acbb5945562dce41d77Jeff Brown for (int i = mProviders.size() - 1; i >= 0; i--) { 833efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mProviders.get(i).stop(); 843efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 853efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 86fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 87fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 88fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private void scanPackages() { 893efa63d3b896244713e84acbb5945562dce41d77Jeff Brown if (!mRunning) { 903efa63d3b896244713e84acbb5945562dce41d77Jeff Brown return; 913efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 923efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 93fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Add providers for all new services. 94fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Reorder the list so that providers left at the end will be the ones to remove. 95fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int targetIndex = 0; 96fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Intent intent = new Intent(MediaRouteProviderService.SERVICE_INTERFACE); 97fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (ResolveInfo resolveInfo : mPackageManager.queryIntentServices(intent, 0)) { 98fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown ServiceInfo serviceInfo = resolveInfo.serviceInfo; 99fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (serviceInfo != null) { 100fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name); 101fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (sourceIndex < 0) { 102fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RegisteredMediaRouteProvider provider = 103fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new RegisteredMediaRouteProvider(mContext, 104fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown new ComponentName(serviceInfo.packageName, serviceInfo.name)); 105f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown provider.start(); 106fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.add(targetIndex++, provider); 1073efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mCallback.addProvider(provider); 108fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } else if (sourceIndex >= targetIndex) { 109fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RegisteredMediaRouteProvider provider = mProviders.get(sourceIndex); 1103efa63d3b896244713e84acbb5945562dce41d77Jeff Brown provider.start(); // restart the provider if needed 111fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown provider.rebindIfDisconnected(); 112fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown Collections.swap(mProviders, sourceIndex, targetIndex++); 113fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 114fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 115fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 116fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 117fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown // Remove providers for missing services. 118fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (targetIndex < mProviders.size()) { 119fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = mProviders.size() - 1; i >= targetIndex; i--) { 120fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RegisteredMediaRouteProvider provider = mProviders.get(i); 1213efa63d3b896244713e84acbb5945562dce41d77Jeff Brown mCallback.removeProvider(provider); 122fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown mProviders.remove(provider); 123f03da4a9e6cc02251c2f804eb6f25da61821d6a7Jeff Brown provider.stop(); 124fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 125fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 126fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 127fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown 128fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown private int findProvider(String packageName, String className) { 129fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown int count = mProviders.size(); 130fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown for (int i = 0; i < count; i++) { 131fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown RegisteredMediaRouteProvider provider = mProviders.get(i); 132fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown if (provider.hasComponentName(packageName, className)) { 133fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return i; 134fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 135fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 136fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown return -1; 137fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown } 1383efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 1393efa63d3b896244713e84acbb5945562dce41d77Jeff Brown private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() { 1403efa63d3b896244713e84acbb5945562dce41d77Jeff Brown @Override 1413efa63d3b896244713e84acbb5945562dce41d77Jeff Brown public void onReceive(Context context, Intent intent) { 1423efa63d3b896244713e84acbb5945562dce41d77Jeff Brown scanPackages(); 1433efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 1443efa63d3b896244713e84acbb5945562dce41d77Jeff Brown }; 1453efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 1463efa63d3b896244713e84acbb5945562dce41d77Jeff Brown private final Runnable mScanPackagesRunnable = new Runnable() { 1473efa63d3b896244713e84acbb5945562dce41d77Jeff Brown @Override 1483efa63d3b896244713e84acbb5945562dce41d77Jeff Brown public void run() { 1493efa63d3b896244713e84acbb5945562dce41d77Jeff Brown scanPackages(); 1503efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 1513efa63d3b896244713e84acbb5945562dce41d77Jeff Brown }; 1523efa63d3b896244713e84acbb5945562dce41d77Jeff Brown 1533efa63d3b896244713e84acbb5945562dce41d77Jeff Brown public interface Callback { 1543efa63d3b896244713e84acbb5945562dce41d77Jeff Brown void addProvider(MediaRouteProvider provider); 1553efa63d3b896244713e84acbb5945562dce41d77Jeff Brown void removeProvider(MediaRouteProvider provider); 1563efa63d3b896244713e84acbb5945562dce41d77Jeff Brown } 157fa326a4649d9d0e8113e315f6c8251fe686abce4Jeff Brown} 158