Home | History | Annotate | Download | only in content
      1 /*
      2  * Copyright (C) 2010 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 com.android.internal.content;
     18 
     19 import android.app.Activity;
     20 import android.content.Context;
     21 import android.content.Intent;
     22 import android.content.IntentFilter;
     23 import android.net.Uri;
     24 
     25 import java.util.HashSet;
     26 
     27 /**
     28  * Helper class for monitoring the state of packages: adding, removing,
     29  * updating, and disappearing and reappearing on the SD card.
     30  */
     31 public abstract class PackageMonitor extends android.content.BroadcastReceiver {
     32     static final IntentFilter sPackageFilt = new IntentFilter();
     33     static final IntentFilter sNonDataFilt = new IntentFilter();
     34     static final IntentFilter sExternalFilt = new IntentFilter();
     35 
     36     static {
     37         sPackageFilt.addAction(Intent.ACTION_PACKAGE_ADDED);
     38         sPackageFilt.addAction(Intent.ACTION_PACKAGE_REMOVED);
     39         sPackageFilt.addAction(Intent.ACTION_PACKAGE_CHANGED);
     40         sPackageFilt.addAction(Intent.ACTION_QUERY_PACKAGE_RESTART);
     41         sPackageFilt.addAction(Intent.ACTION_PACKAGE_RESTARTED);
     42         sPackageFilt.addAction(Intent.ACTION_UID_REMOVED);
     43         sPackageFilt.addDataScheme("package");
     44         sNonDataFilt.addAction(Intent.ACTION_UID_REMOVED);
     45         sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);
     46         sExternalFilt.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);
     47     }
     48 
     49     final HashSet<String> mUpdatingPackages = new HashSet<String>();
     50 
     51     Context mRegisteredContext;
     52     String[] mDisappearingPackages;
     53     String[] mAppearingPackages;
     54     String[] mModifiedPackages;
     55     int mChangeType;
     56     boolean mSomePackagesChanged;
     57 
     58     String[] mTempArray = new String[1];
     59 
     60     public void register(Context context, boolean externalStorage) {
     61         if (mRegisteredContext != null) {
     62             throw new IllegalStateException("Already registered");
     63         }
     64         mRegisteredContext = context;
     65         context.registerReceiver(this, sPackageFilt);
     66         context.registerReceiver(this, sNonDataFilt);
     67         if (externalStorage) {
     68             context.registerReceiver(this, sExternalFilt);
     69         }
     70     }
     71 
     72     public void unregister() {
     73         if (mRegisteredContext == null) {
     74             throw new IllegalStateException("Not registered");
     75         }
     76         mRegisteredContext.unregisterReceiver(this);
     77         mRegisteredContext = null;
     78     }
     79 
     80     //not yet implemented
     81     boolean isPackageUpdating(String packageName) {
     82         synchronized (mUpdatingPackages) {
     83             return mUpdatingPackages.contains(packageName);
     84         }
     85     }
     86 
     87     public void onBeginPackageChanges() {
     88     }
     89 
     90     public void onPackageAdded(String packageName, int uid) {
     91     }
     92 
     93     public void onPackageRemoved(String packageName, int uid) {
     94     }
     95 
     96     public void onPackageUpdateStarted(String packageName, int uid) {
     97     }
     98 
     99     public void onPackageUpdateFinished(String packageName, int uid) {
    100     }
    101 
    102     public void onPackageChanged(String packageName, int uid, String[] components) {
    103     }
    104 
    105     public boolean onHandleForceStop(Intent intent, String[] packages, int uid, boolean doit) {
    106         return false;
    107     }
    108 
    109     public void onUidRemoved(int uid) {
    110     }
    111 
    112     public void onPackagesAvailable(String[] packages) {
    113     }
    114 
    115     public void onPackagesUnavailable(String[] packages) {
    116     }
    117 
    118     public static final int PACKAGE_UNCHANGED = 0;
    119     public static final int PACKAGE_UPDATING = 1;
    120     public static final int PACKAGE_TEMPORARY_CHANGE = 2;
    121     public static final int PACKAGE_PERMANENT_CHANGE = 3;
    122 
    123     public void onPackageDisappeared(String packageName, int reason) {
    124     }
    125 
    126     public void onPackageAppeared(String packageName, int reason) {
    127     }
    128 
    129     public void onPackageModified(String packageName) {
    130     }
    131 
    132     public boolean didSomePackagesChange() {
    133         return mSomePackagesChanged;
    134     }
    135 
    136     public int isPackageAppearing(String packageName) {
    137         if (mAppearingPackages != null) {
    138             for (int i=mAppearingPackages.length-1; i>=0; i--) {
    139                 if (packageName.equals(mAppearingPackages[i])) {
    140                     return mChangeType;
    141                 }
    142             }
    143         }
    144         return PACKAGE_UNCHANGED;
    145     }
    146 
    147     public boolean anyPackagesAppearing() {
    148         return mAppearingPackages != null;
    149     }
    150 
    151     public int isPackageDisappearing(String packageName) {
    152         if (mDisappearingPackages != null) {
    153             for (int i=mDisappearingPackages.length-1; i>=0; i--) {
    154                 if (packageName.equals(mDisappearingPackages[i])) {
    155                     return mChangeType;
    156                 }
    157             }
    158         }
    159         return PACKAGE_UNCHANGED;
    160     }
    161 
    162     public boolean anyPackagesDisappearing() {
    163         return mDisappearingPackages != null;
    164     }
    165 
    166     public boolean isPackageModified(String packageName) {
    167         if (mModifiedPackages != null) {
    168             for (int i=mModifiedPackages.length-1; i>=0; i--) {
    169                 if (packageName.equals(mModifiedPackages[i])) {
    170                     return true;
    171                 }
    172             }
    173         }
    174         return false;
    175     }
    176 
    177     public void onSomePackagesChanged() {
    178     }
    179 
    180     public void onFinishPackageChanges() {
    181     }
    182 
    183     String getPackageName(Intent intent) {
    184         Uri uri = intent.getData();
    185         String pkg = uri != null ? uri.getSchemeSpecificPart() : null;
    186         return pkg;
    187     }
    188 
    189     @Override
    190     public void onReceive(Context context, Intent intent) {
    191         onBeginPackageChanges();
    192 
    193         mDisappearingPackages = mAppearingPackages = null;
    194         mSomePackagesChanged = false;
    195 
    196         String action = intent.getAction();
    197         if (Intent.ACTION_PACKAGE_ADDED.equals(action)) {
    198             String pkg = getPackageName(intent);
    199             int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
    200             // We consider something to have changed regardless of whether
    201             // this is just an update, because the update is now finished
    202             // and the contents of the package may have changed.
    203             mSomePackagesChanged = true;
    204             if (pkg != null) {
    205                 mAppearingPackages = mTempArray;
    206                 mTempArray[0] = pkg;
    207                 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
    208                     mModifiedPackages = mTempArray;
    209                     mChangeType = PACKAGE_UPDATING;
    210                     onPackageUpdateFinished(pkg, uid);
    211                     onPackageModified(pkg);
    212                 } else {
    213                     mChangeType = PACKAGE_PERMANENT_CHANGE;
    214                     onPackageAdded(pkg, uid);
    215                 }
    216                 onPackageAppeared(pkg, mChangeType);
    217                 if (mChangeType == PACKAGE_UPDATING) {
    218                     synchronized (mUpdatingPackages) {
    219                         mUpdatingPackages.remove(pkg);
    220                     }
    221                 }
    222             }
    223         } else if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) {
    224             String pkg = getPackageName(intent);
    225             int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
    226             if (pkg != null) {
    227                 mDisappearingPackages = mTempArray;
    228                 mTempArray[0] = pkg;
    229                 if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
    230                     mChangeType = PACKAGE_UPDATING;
    231                     synchronized (mUpdatingPackages) {
    232                         //not used for now
    233                         //mUpdatingPackages.add(pkg);
    234                     }
    235                     onPackageUpdateStarted(pkg, uid);
    236                 } else {
    237                     mChangeType = PACKAGE_PERMANENT_CHANGE;
    238                     // We only consider something to have changed if this is
    239                     // not a replace; for a replace, we just need to consider
    240                     // it when it is re-added.
    241                     mSomePackagesChanged = true;
    242                     onPackageRemoved(pkg, uid);
    243                 }
    244                 onPackageDisappeared(pkg, mChangeType);
    245             }
    246         } else if (Intent.ACTION_PACKAGE_CHANGED.equals(action)) {
    247             String pkg = getPackageName(intent);
    248             int uid = intent.getIntExtra(Intent.EXTRA_UID, 0);
    249             String[] components = intent.getStringArrayExtra(
    250                     Intent.EXTRA_CHANGED_COMPONENT_NAME_LIST);
    251             if (pkg != null) {
    252                 mModifiedPackages = mTempArray;
    253                 mTempArray[0] = pkg;
    254                 onPackageChanged(pkg, uid, components);
    255                 // XXX Don't want this to always cause mSomePackagesChanged,
    256                 // since it can happen a fair amount.
    257                 onPackageModified(pkg);
    258             }
    259         } else if (Intent.ACTION_QUERY_PACKAGE_RESTART.equals(action)) {
    260             mDisappearingPackages = intent.getStringArrayExtra(Intent.EXTRA_PACKAGES);
    261             mChangeType = PACKAGE_TEMPORARY_CHANGE;
    262             boolean canRestart = onHandleForceStop(intent,
    263                     mDisappearingPackages,
    264                     intent.getIntExtra(Intent.EXTRA_UID, 0), false);
    265             if (canRestart) setResultCode(Activity.RESULT_OK);
    266         } else if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
    267             mDisappearingPackages = new String[] {getPackageName(intent)};
    268             mChangeType = PACKAGE_TEMPORARY_CHANGE;
    269             onHandleForceStop(intent, mDisappearingPackages,
    270                     intent.getIntExtra(Intent.EXTRA_UID, 0), true);
    271         } else if (Intent.ACTION_UID_REMOVED.equals(action)) {
    272             onUidRemoved(intent.getIntExtra(Intent.EXTRA_UID, 0));
    273         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE.equals(action)) {
    274             String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    275             mAppearingPackages = pkgList;
    276             mChangeType = PACKAGE_TEMPORARY_CHANGE;
    277             mSomePackagesChanged = true;
    278             if (pkgList != null) {
    279                 onPackagesAvailable(pkgList);
    280                 for (int i=0; i<pkgList.length; i++) {
    281                     onPackageAppeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
    282                 }
    283             }
    284         } else if (Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE.equals(action)) {
    285             String[] pkgList = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);
    286             mDisappearingPackages = pkgList;
    287             mChangeType = PACKAGE_TEMPORARY_CHANGE;
    288             mSomePackagesChanged = true;
    289             if (pkgList != null) {
    290                 onPackagesUnavailable(pkgList);
    291                 for (int i=0; i<pkgList.length; i++) {
    292                     onPackageDisappeared(pkgList[i], PACKAGE_TEMPORARY_CHANGE);
    293                 }
    294             }
    295         }
    296 
    297         if (mSomePackagesChanged) {
    298             onSomePackagesChanged();
    299         }
    300 
    301         onFinishPackageChanges();
    302     }
    303 }
    304