131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project/*
231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Copyright (C) 2008 The Android Open Source Project
331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * you may not use this file except in compliance with the License.
631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * You may obtain a copy of the License at
731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project *
1031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
1131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
1231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * See the License for the specific language governing permissions and
1431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project * limitations under the License.
1531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project */
1631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
17325dc23624160689e59fbac708cf6f222b20d025Daniel Sandlerpackage com.android.launcher3;
1831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
1931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.BroadcastReceiver;
20f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chungimport android.content.ContentResolver;
2131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Context;
2231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.content.Intent;
2331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.database.Cursor;
2431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport android.net.Uri;
25d93a7d1716b06cd65f45dfc16232277d0d57c04dRomain Guyimport android.widget.Toast;
2631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
2731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectimport java.net.URISyntaxException;
28f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chungimport java.util.ArrayList;
29f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chungimport java.util.Iterator;
3031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
3131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Projectpublic class UninstallShortcutReceiver extends BroadcastReceiver {
3251ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy    private static final String ACTION_UNINSTALL_SHORTCUT =
3394d6768c65929efa21bb893fdef7f269d65da3c3Winson Chung            "com.android.launcher.action.UNINSTALL_SHORTCUT";
3451ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy
35f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    // The set of shortcuts that are pending uninstall
36f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    private static ArrayList<PendingUninstallShortcutInfo> mUninstallQueue =
37f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung            new ArrayList<PendingUninstallShortcutInfo>();
38f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
39f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    // Determines whether to defer uninstalling shortcuts immediately until
40f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    // disableAndFlushUninstallQueue() is called.
41f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    private static boolean mUseUninstallQueue = false;
42f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
43f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    private static class PendingUninstallShortcutInfo {
44f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        Intent data;
45f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
46f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        public PendingUninstallShortcutInfo(Intent rawData) {
47f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung            data = rawData;
48f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        }
49f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    }
50f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
5131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    public void onReceive(Context context, Intent data) {
5251ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy        if (!ACTION_UNINSTALL_SHORTCUT.equals(data.getAction())) {
5351ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy            return;
5451ed5b9bc05c6eb37dcb3fe38fa021f1044c0f88Romain Guy        }
55f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
56f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        PendingUninstallShortcutInfo info = new PendingUninstallShortcutInfo(data);
57f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        if (mUseUninstallQueue) {
58f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung            mUninstallQueue.add(info);
59f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        } else {
60f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung            processUninstallShortcut(context, info);
61f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        }
62f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    }
63f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
64f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    static void enableUninstallQueue() {
65f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        mUseUninstallQueue = true;
66f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    }
67f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
68f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    static void disableAndFlushUninstallQueue(Context context) {
69f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        mUseUninstallQueue = false;
70f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        Iterator<PendingUninstallShortcutInfo> iter = mUninstallQueue.iterator();
71f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        while (iter.hasNext()) {
72f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung            processUninstallShortcut(context, iter.next());
73f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung            iter.remove();
74f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        }
75f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    }
76f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
77f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung    private static void processUninstallShortcut(Context context,
78f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung            PendingUninstallShortcutInfo pendingInfo) {
79f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung        final Intent data = pendingInfo.data;
80f561bdf68dd304e1d7c3f7796621a4cc39ca15f2Winson Chung
81c88dceb0b567ab96418e73cf2f6b197ba2646cb3Winson Chung        LauncherAppState.setApplicationContext(context.getApplicationContext());
82cc8befac3550c81d04ea206c170adae36c9a6c93Daniel Sandler        LauncherAppState app = LauncherAppState.getInstance();
83e4f9891f01bdc10d8f96e4e2429e2f4d0558238bDaniel Sandler        synchronized (app) { // TODO: make removeShortcut internally threadsafe
84997a92348a6d6e061737399321393449c16cd4d8Winson Chung            removeShortcut(context, data);
85a2413751e3a698aef9c87411a639637883856939Winson Chung        }
86a2413751e3a698aef9c87411a639637883856939Winson Chung    }
87a2413751e3a698aef9c87411a639637883856939Winson Chung
88997a92348a6d6e061737399321393449c16cd4d8Winson Chung    private static void removeShortcut(Context context, Intent data) {
8931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
9031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
9131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        boolean duplicate = data.getBooleanExtra(Launcher.EXTRA_SHORTCUT_DUPLICATE, true);
9231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
9331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        if (intent != null && name != null) {
9431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            final ContentResolver cr = context.getContentResolver();
9531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
9673b979d8c141c7ceac82dad7c5b271a6a42afa67Romain Guy                new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.INTENT },
9731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                LauncherSettings.Favorites.TITLE + "=?", new String[] { name }, null);
9831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
9931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
10031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
10131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            boolean changed = false;
10331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
10431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            try {
10531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                while (c.moveToNext()) {
10631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    try {
1071ce1a24cba4dc41bccfeab6fccb2f3355423841aRomain Guy                        if (intent.filterEquals(Intent.parseUri(c.getString(intentIndex), 0))) {
10831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                            final long id = c.getLong(idIndex);
10931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                            final Uri uri = LauncherSettings.Favorites.getContentUri(id, false);
11031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                            cr.delete(uri, null, null);
11131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                            changed = true;
11231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                            if (!duplicate) {
11331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                                break;
11431dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                            }
11531dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        }
11631dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    } catch (URISyntaxException e) {
11731dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                        // Ignore
11831dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                    }
11931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                }
12031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            } finally {
12131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project                c.close();
12231dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project            }
12331dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project
124d93a7d1716b06cd65f45dfc16232277d0d57c04dRomain Guy            if (changed) {
125d93a7d1716b06cd65f45dfc16232277d0d57c04dRomain Guy                cr.notifyChange(LauncherSettings.Favorites.CONTENT_URI, null);
126d93a7d1716b06cd65f45dfc16232277d0d57c04dRomain Guy                Toast.makeText(context, context.getString(R.string.shortcut_uninstalled, name),
127d93a7d1716b06cd65f45dfc16232277d0d57c04dRomain Guy                        Toast.LENGTH_SHORT).show();
128d93a7d1716b06cd65f45dfc16232277d0d57c04dRomain Guy            }
12931dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project        }
13031dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project    }
13131dd503c6aa69018e694d91724d46db49ea09327The Android Open Source Project}
132