Home | History | Annotate | Download | only in media
      1 /*
      2  * Copyright (C) 2013 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package androidx.mediarouter.media;
     18 
     19 import android.content.BroadcastReceiver;
     20 import android.content.ComponentName;
     21 import android.content.Context;
     22 import android.content.Intent;
     23 import android.content.IntentFilter;
     24 import android.content.pm.PackageManager;
     25 import android.content.pm.ResolveInfo;
     26 import android.content.pm.ServiceInfo;
     27 import android.os.Handler;
     28 
     29 import java.util.ArrayList;
     30 import java.util.Collections;
     31 
     32 /**
     33  * Watches for media route provider services to be installed.
     34  * Adds a provider to the media router for each registered service.
     35  *
     36  * @see RegisteredMediaRouteProvider
     37  */
     38 final class RegisteredMediaRouteProviderWatcher {
     39     private final Context mContext;
     40     private final Callback mCallback;
     41     private final Handler mHandler;
     42     private final PackageManager mPackageManager;
     43 
     44     private final ArrayList<RegisteredMediaRouteProvider> mProviders =
     45             new ArrayList<RegisteredMediaRouteProvider>();
     46     private boolean mRunning;
     47 
     48     public RegisteredMediaRouteProviderWatcher(Context context, Callback callback) {
     49         mContext = context;
     50         mCallback = callback;
     51         mHandler = new Handler();
     52         mPackageManager = context.getPackageManager();
     53     }
     54 
     55     public void start() {
     56         if (!mRunning) {
     57             mRunning = true;
     58 
     59             IntentFilter filter = new IntentFilter();
     60             filter.addAction(Intent.ACTION_PACKAGE_ADDED);
     61             filter.addAction(Intent.ACTION_PACKAGE_REMOVED);
     62             filter.addAction(Intent.ACTION_PACKAGE_CHANGED);
     63             filter.addAction(Intent.ACTION_PACKAGE_REPLACED);
     64             filter.addAction(Intent.ACTION_PACKAGE_RESTARTED);
     65             filter.addDataScheme("package");
     66             mContext.registerReceiver(mScanPackagesReceiver, filter, null, mHandler);
     67 
     68             // Scan packages.
     69             // Also has the side-effect of restarting providers if needed.
     70             mHandler.post(mScanPackagesRunnable);
     71         }
     72     }
     73 
     74     public void stop() {
     75         if (mRunning) {
     76             mRunning = false;
     77 
     78             mContext.unregisterReceiver(mScanPackagesReceiver);
     79             mHandler.removeCallbacks(mScanPackagesRunnable);
     80 
     81             // Stop all providers.
     82             for (int i = mProviders.size() - 1; i >= 0; i--) {
     83                 mProviders.get(i).stop();
     84             }
     85         }
     86     }
     87 
     88     void scanPackages() {
     89         if (!mRunning) {
     90             return;
     91         }
     92 
     93         // Add providers for all new services.
     94         // Reorder the list so that providers left at the end will be the ones to remove.
     95         int targetIndex = 0;
     96         Intent intent = new Intent(MediaRouteProviderService.SERVICE_INTERFACE);
     97         for (ResolveInfo resolveInfo : mPackageManager.queryIntentServices(intent, 0)) {
     98             ServiceInfo serviceInfo = resolveInfo.serviceInfo;
     99             if (serviceInfo != null) {
    100                 int sourceIndex = findProvider(serviceInfo.packageName, serviceInfo.name);
    101                 if (sourceIndex < 0) {
    102                     RegisteredMediaRouteProvider provider =
    103                             new RegisteredMediaRouteProvider(mContext,
    104                             new ComponentName(serviceInfo.packageName, serviceInfo.name));
    105                     provider.start();
    106                     mProviders.add(targetIndex++, provider);
    107                     mCallback.addProvider(provider);
    108                 } else if (sourceIndex >= targetIndex) {
    109                     RegisteredMediaRouteProvider provider = mProviders.get(sourceIndex);
    110                     provider.start(); // restart the provider if needed
    111                     provider.rebindIfDisconnected();
    112                     Collections.swap(mProviders, sourceIndex, targetIndex++);
    113                 }
    114             }
    115         }
    116 
    117         // Remove providers for missing services.
    118         if (targetIndex < mProviders.size()) {
    119             for (int i = mProviders.size() - 1; i >= targetIndex; i--) {
    120                 RegisteredMediaRouteProvider provider = mProviders.get(i);
    121                 mCallback.removeProvider(provider);
    122                 mProviders.remove(provider);
    123                 provider.stop();
    124             }
    125         }
    126     }
    127 
    128     private int findProvider(String packageName, String className) {
    129         int count = mProviders.size();
    130         for (int i = 0; i < count; i++) {
    131             RegisteredMediaRouteProvider provider = mProviders.get(i);
    132             if (provider.hasComponentName(packageName, className)) {
    133                 return i;
    134             }
    135         }
    136         return -1;
    137     }
    138 
    139     private final BroadcastReceiver mScanPackagesReceiver = new BroadcastReceiver() {
    140         @Override
    141         public void onReceive(Context context, Intent intent) {
    142             scanPackages();
    143         }
    144     };
    145 
    146     private final Runnable mScanPackagesRunnable = new Runnable() {
    147         @Override
    148         public void run() {
    149             scanPackages();
    150         }
    151     };
    152 
    153     public interface Callback {
    154         void addProvider(MediaRouteProvider provider);
    155         void removeProvider(MediaRouteProvider provider);
    156     }
    157 }
    158