1c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project/**
2c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
3c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project *
4c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * use this file except in compliance with the License. You may obtain a copy
6c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * of the License at
7c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project *
8c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0
9c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project *
10c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
11c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * License for the specific language governing permissions and limitations
14c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * under the License.
15c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project */
16c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
17c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectpackage com.android.internal.policy.impl;
18c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
19c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.content.Context;
20c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.content.Intent;
21c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.database.ContentObserver;
22c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.database.Cursor;
23c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.os.Handler;
24c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.provider.Settings;
25c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.util.Log;
26c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.util.SparseArray;
27c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport android.view.KeyCharacterMap;
28c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
29c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectimport java.net.URISyntaxException;
30c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
31c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project/**
32c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * Manages quick launch shortcuts by:
33c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * <li> Keeping the local copy in sync with the database (this is an observer)
34c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project * <li> Returning a shortcut-matching intent to clients
35c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project */
36c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Projectclass ShortcutManager extends ContentObserver {
37c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
38c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private static final String TAG = "ShortcutManager";
39c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
40c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private static final int COLUMN_SHORTCUT = 0;
41c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private static final int COLUMN_INTENT = 1;
42c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private static final String[] sProjection = new String[] {
43c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT
44c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    };
45c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
46c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private Context mContext;
47c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private Cursor mCursor;
48c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    /** Map of a shortcut to its intent. */
49c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private SparseArray<Intent> mShortcutIntents;
50c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
51c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    public ShortcutManager(Context context, Handler handler) {
52c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        super(handler);
53c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
54c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        mContext = context;
55c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        mShortcutIntents = new SparseArray<Intent>();
56c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    }
57c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
58c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    /** Observes the provider of shortcut+intents */
59c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    public void observe() {
60c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        mCursor = mContext.getContentResolver().query(
61c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project                Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null);
62c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        mCursor.registerContentObserver(this);
63c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        updateShortcuts();
64c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    }
65c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
66c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    @Override
67c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    public void onChange(boolean selfChange) {
68c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        updateShortcuts();
69c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    }
70c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
71c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    private void updateShortcuts() {
72c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        Cursor c = mCursor;
73c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        if (!c.requery()) {
74c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            Log.e(TAG, "ShortcutObserver could not re-query shortcuts.");
75c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            return;
76c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        }
77c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
78c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        mShortcutIntents.clear();
79c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        while (c.moveToNext()) {
80c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            int shortcut = c.getInt(COLUMN_SHORTCUT);
81c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            if (shortcut == 0) continue;
82c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            String intentURI = c.getString(COLUMN_INTENT);
83c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            Intent intent = null;
84c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            try {
85c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project                intent = Intent.getIntent(intentURI);
86c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            } catch (URISyntaxException e) {
87c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project                Log.w(TAG, "Intent URI for shortcut invalid.", e);
88c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            }
89c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            if (intent == null) continue;
90c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project            mShortcutIntents.put(shortcut, intent);
91c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        }
92c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    }
93c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
94c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    /**
95c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * Gets the shortcut intent for a given keycode+modifier. Make sure you
96c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * strip whatever modifier is used for invoking shortcuts (for example,
97c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
98c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * 'Sym' bit from the modifiers before calling this method.
99c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * <p>
100c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * This will first try an exact match (with modifiers), and then try a
101c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * match without modifiers (primary character on a key).
102c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     *
103c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * @param keyCode The keycode of the key pushed.
104c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * @param modifiers The modifiers without any that are used for chording
105c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     *            to invoke a shortcut.
106c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     * @return The intent that matches the shortcut, or null if not found.
107c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project     */
108c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    public Intent getIntent(int keyCode, int modifiers) {
109c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        KeyCharacterMap kcm = KeyCharacterMap.load(KeyCharacterMap.BUILT_IN_KEYBOARD);
110c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        // First try the exact keycode (with modifiers)
111c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        int shortcut = kcm.get(keyCode, modifiers);
112c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        Intent intent = shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
113c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        if (intent != null) return intent;
114c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
115c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        // Next try the keycode without modifiers (the primary character on that key)
116c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        shortcut = Character.toLowerCase(kcm.get(keyCode, 0));
117c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project        return shortcut != 0 ? mShortcutIntents.get(shortcut) : null;
118c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project    }
119c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project
120c5d93b3b6a0ba4831903f8e8d1664c4470cf15d7The Android Open Source Project}
121