126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen/*
226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * Copyright (C) 2013 The Android Open Source Project
326515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen *
426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * Licensed under the Apache License, Version 2.0 (the "License");
526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * you may not use this file except in compliance with the License.
626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * You may obtain a copy of the License at
726515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen *
826515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen *      http://www.apache.org/licenses/LICENSE-2.0
926515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen *
1026515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * Unless required by applicable law or agreed to in writing, software
1126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * distributed under the License is distributed on an "AS IS" BASIS,
1226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1326515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * See the License for the specific language governing permissions and
1426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen * limitations under the License.
1526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen */
1626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
1726515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenpackage com.android.settings.nfc;
1826515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
19fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport android.app.Activity;
206d5cac594620bd270f263fedfb8a23d6d916b014Martijn Coenenimport android.content.ComponentName;
216d5cac594620bd270f263fedfb8a23d6d916b014Martijn Coenenimport android.content.Context;
2226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenimport android.content.pm.PackageManager;
23fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport android.content.res.Resources;
2426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenimport android.graphics.drawable.Drawable;
2526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenimport android.nfc.NfcAdapter;
2626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenimport android.nfc.cardemulation.ApduServiceInfo;
27a73aa32278adb177042d4b5c873a0f08deb1d3f3Martijn Coenenimport android.nfc.cardemulation.CardEmulation;
28fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport android.os.Bundle;
29fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport android.os.Handler;
30fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport android.os.Message;
31fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport android.os.UserHandle;
3226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenimport android.provider.Settings;
3300dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenenimport android.provider.Settings.SettingNotFoundException;
34fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport android.util.Log;
35fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenenimport com.android.internal.content.PackageMonitor;
3626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
3726515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenimport java.util.ArrayList;
3826515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenimport java.util.List;
3926515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
4026515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenenpublic class PaymentBackend {
4126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    public static final String TAG = "Settings.PaymentBackend";
4226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
43fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public interface Callback {
44fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        void onPaymentAppsChanged();
45fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
46fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
4726515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    public static class PaymentAppInfo {
48fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        CharSequence label;
49fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        CharSequence description;
50da6c0ba382c1c2c9b98f11a1ef9e572472654e27Martijn Coenen        Drawable banner;
5126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        boolean isDefault;
5226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        public ComponentName componentName;
53fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        public ComponentName settingsComponent;
5426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    }
5526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
5626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    private final Context mContext;
5726515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    private final NfcAdapter mAdapter;
58a73aa32278adb177042d4b5c873a0f08deb1d3f3Martijn Coenen    private final CardEmulation mCardEmuManager;
59fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    private final PackageMonitor mSettingsPackageMonitor = new SettingsPackageMonitor();
60fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    // Fields below only modified on UI thread
61fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    private ArrayList<PaymentAppInfo> mAppInfos;
62fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    private PaymentAppInfo mDefaultAppInfo;
63fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    private ArrayList<Callback> mCallbacks = new ArrayList<Callback>();
6426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
6526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    public PaymentBackend(Context context) {
6626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        mContext = context;
6726515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
6826515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        mAdapter = NfcAdapter.getDefaultAdapter(context);
69a73aa32278adb177042d4b5c873a0f08deb1d3f3Martijn Coenen        mCardEmuManager = CardEmulation.getInstance(mAdapter);
70fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        refresh();
7126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    }
7226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
73fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public void onPause() {
74fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        mSettingsPackageMonitor.unregister();
75fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
76fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
77fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public void onResume() {
78fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        mSettingsPackageMonitor.register(mContext, mContext.getMainLooper(), false);
79fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
80fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
81fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public void refresh() {
8226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        PackageManager pm = mContext.getPackageManager();
8326515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        List<ApduServiceInfo> serviceInfos =
84a73aa32278adb177042d4b5c873a0f08deb1d3f3Martijn Coenen                mCardEmuManager.getServices(CardEmulation.CATEGORY_PAYMENT);
85fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        ArrayList<PaymentAppInfo> appInfos = new ArrayList<PaymentAppInfo>();
8626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
87fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        if (serviceInfos == null) {
88fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            makeCallbacks();
89fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            return;
90fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
9126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
92fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        ComponentName defaultAppName = getDefaultPaymentApp();
93fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        PaymentAppInfo foundDefaultApp = null;
9426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        for (ApduServiceInfo service : serviceInfos) {
9526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen            PaymentAppInfo appInfo = new PaymentAppInfo();
96fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            appInfo.label = service.loadLabel(pm);
97fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            if (appInfo.label == null) {
98fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen                appInfo.label = service.loadAppLabel(pm);
99fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            }
100fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            appInfo.isDefault = service.getComponent().equals(defaultAppName);
101fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            if (appInfo.isDefault) {
102fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen                foundDefaultApp = appInfo;
1030e940d6c00d06578c4c0f89a95e5d31c8073fbc1Martijn Coenen            }
10426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen            appInfo.componentName = service.getComponent();
105fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            String settingsActivity = service.getSettingsActivityName();
106fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            if (settingsActivity != null) {
107fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen                appInfo.settingsComponent = new ComponentName(appInfo.componentName.getPackageName(),
108fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen                        settingsActivity);
109fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            } else {
110fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen                appInfo.settingsComponent = null;
111fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            }
1126d5cac594620bd270f263fedfb8a23d6d916b014Martijn Coenen            appInfo.description = service.getDescription();
1136d5cac594620bd270f263fedfb8a23d6d916b014Martijn Coenen            appInfo.banner = service.loadBanner(pm);
11426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen            appInfos.add(appInfo);
11526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        }
116fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        mAppInfos = appInfos;
117fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        mDefaultAppInfo = foundDefaultApp;
118fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        makeCallbacks();
119fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
120fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
121fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public void registerCallback(Callback callback) {
122fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        mCallbacks.add(callback);
123fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
124fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
125fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public void unregisterCallback(Callback callback) {
126fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        mCallbacks.remove(callback);
127fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
128fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
129fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public List<PaymentAppInfo> getPaymentAppInfos() {
130fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        return mAppInfos;
131fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
132fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
133fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    public PaymentAppInfo getDefaultApp() {
134fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        return mDefaultAppInfo;
135fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
136fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
137fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    void makeCallbacks() {
138fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        for (Callback callback : mCallbacks) {
139fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            callback.onPaymentAppsChanged();
140fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
141fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
142fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
143fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    Drawable loadDrawableForPackage(String pkgName, int drawableResId) {
144fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        PackageManager pm = mContext.getPackageManager();
145fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        try {
146fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            Resources res = pm.getResourcesForApplication(pkgName);
147fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            Drawable banner = res.getDrawable(drawableResId);
148fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            return banner;
149fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        } catch (Resources.NotFoundException e) {
150fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            return null;
151fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        } catch (PackageManager.NameNotFoundException e) {
152fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            return null;
153fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
154fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
15526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
15600dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen    boolean isForegroundMode() {
15700dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen        try {
15800dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen            return Settings.Secure.getInt(mContext.getContentResolver(),
15900dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen                    Settings.Secure.NFC_PAYMENT_FOREGROUND) != 0;
16000dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen        } catch (SettingNotFoundException e) {
16100dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen            return false;
16200dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen        }
16300dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen    }
16400dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen
16500dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen    void setForegroundMode(boolean foreground) {
16600dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen        Settings.Secure.putInt(mContext.getContentResolver(),
16700dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen                Settings.Secure.NFC_PAYMENT_FOREGROUND, foreground ? 1 : 0) ;
16800dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen    }
16900dbb74b8d699510ece683fc7ab12fc2343fa5d5Martijn Coenen
17026515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    ComponentName getDefaultPaymentApp() {
17126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        String componentString = Settings.Secure.getString(mContext.getContentResolver(),
17226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen                Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT);
17326515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        if (componentString != null) {
17426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen            return ComponentName.unflattenFromString(componentString);
17526515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        } else {
17626515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen            return null;
17726515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        }
17826515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    }
17926515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen
18026515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    public void setDefaultPaymentApp(ComponentName app) {
18126515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen        Settings.Secure.putString(mContext.getContentResolver(),
18226515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen                Settings.Secure.NFC_PAYMENT_DEFAULT_COMPONENT,
18326515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen                app != null ? app.flattenToString() : null);
184fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        refresh();
185fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    }
186fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
187fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    private final Handler mHandler = new Handler() {
188fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        @Override
189fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        public void dispatchMessage(Message msg) {
190fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            refresh();
191fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
192fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    };
193fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
194fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen    private class SettingsPackageMonitor extends PackageMonitor {
195fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        @Override
196fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        public void onPackageAdded(String packageName, int uid) {
197fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            mHandler.obtainMessage().sendToTarget();
198fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
199fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
200fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        @Override
201fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        public void onPackageAppeared(String packageName, int reason) {
202fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            mHandler.obtainMessage().sendToTarget();
203fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
204fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
205fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        @Override
206fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        public void onPackageDisappeared(String packageName, int reason) {
207fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            mHandler.obtainMessage().sendToTarget();
208fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
209fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen
210fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        @Override
211fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        public void onPackageRemoved(String packageName, int uid) {
212fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen            mHandler.obtainMessage().sendToTarget();
213fe58b534f6a1bf63dadb18dae13c59ed8a014eecMartijn Coenen        }
21426515da08707b6f8182cc8b0ed5e01e97aa92a96Martijn Coenen    }
2156d5cac594620bd270f263fedfb8a23d6d916b014Martijn Coenen}
216