11f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project/*
21f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Copyright (C) 2007 The Android Open Source Project
31f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
41f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License");
51f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * you may not use this file except in compliance with the License.
61f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * You may obtain a copy of the License at
71f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
81f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *      http://www.apache.org/licenses/LICENSE-2.0
91f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project *
101f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Unless required by applicable law or agreed to in writing, software
111f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS,
121f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
131f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * See the License for the specific language governing permissions and
141f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * limitations under the License.
151f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project */
161f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
171f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectpackage com.android.internal.policy.impl;
181f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
191f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.content.Context;
201f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.content.Intent;
211f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.database.ContentObserver;
221f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.database.Cursor;
231f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.os.Handler;
241f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.provider.Settings;
251f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.util.Log;
261f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.util.SparseArray;
271f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport android.view.KeyCharacterMap;
281f2451007c660091b7b090c1ea332f9044515d2dJeff Brownimport android.view.KeyEvent;
291f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
301f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectimport java.net.URISyntaxException;
311f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
321f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project/**
331f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * Manages quick launch shortcuts by:
341f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * <li> Keeping the local copy in sync with the database (this is an observer)
351f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project * <li> Returning a shortcut-matching intent to clients
361f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project */
371f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Projectclass ShortcutManager extends ContentObserver {
381f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
391f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private static final String TAG = "ShortcutManager";
401f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
411f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private static final int COLUMN_SHORTCUT = 0;
421f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private static final int COLUMN_INTENT = 1;
431f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private static final String[] sProjection = new String[] {
441f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        Settings.Bookmarks.SHORTCUT, Settings.Bookmarks.INTENT
451f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    };
461f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
471f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private Context mContext;
481f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private Cursor mCursor;
491f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /** Map of a shortcut to its intent. */
501f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private SparseArray<Intent> mShortcutIntents;
511f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
521f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public ShortcutManager(Context context, Handler handler) {
531f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        super(handler);
541f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
551f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mContext = context;
561f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mShortcutIntents = new SparseArray<Intent>();
571f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
581f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
591f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /** Observes the provider of shortcut+intents */
601f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public void observe() {
611f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mCursor = mContext.getContentResolver().query(
621f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                Settings.Bookmarks.CONTENT_URI, sProjection, null, null, null);
631f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mCursor.registerContentObserver(this);
641f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        updateShortcuts();
651f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
661f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
671f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    @Override
681f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    public void onChange(boolean selfChange) {
691f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        updateShortcuts();
701f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
711f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
721f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    private void updateShortcuts() {
731f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        Cursor c = mCursor;
741f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        if (!c.requery()) {
751f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            Log.e(TAG, "ShortcutObserver could not re-query shortcuts.");
761f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            return;
771f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
781f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
791f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        mShortcutIntents.clear();
801f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        while (c.moveToNext()) {
811f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            int shortcut = c.getInt(COLUMN_SHORTCUT);
821f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            if (shortcut == 0) continue;
831f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            String intentURI = c.getString(COLUMN_INTENT);
841f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            Intent intent = null;
851f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            try {
861f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                intent = Intent.getIntent(intentURI);
871f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            } catch (URISyntaxException e) {
881f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project                Log.w(TAG, "Intent URI for shortcut invalid.", e);
891f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            }
901f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            if (intent == null) continue;
911f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project            mShortcutIntents.put(shortcut, intent);
921f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project        }
931f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
941f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
951f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    /**
961f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * Gets the shortcut intent for a given keycode+modifier. Make sure you
971f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * strip whatever modifier is used for invoking shortcuts (for example,
981f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * if 'Sym+A' should invoke a shortcut on 'A', you should strip the
991f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * 'Sym' bit from the modifiers before calling this method.
1001f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * <p>
1011f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * This will first try an exact match (with modifiers), and then try a
1021f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * match without modifiers (primary character on a key).
1031f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     *
104c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown     * @param kcm The key character map of the device on which the key was pressed.
105c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown     * @param keyCode The key code.
106c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown     * @param metaState The meta state, omitting any modifiers that were used
107c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown     * to invoke the shortcut.
1081f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     * @return The intent that matches the shortcut, or null if not found.
1091f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project     */
110c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown    public Intent getIntent(KeyCharacterMap kcm, int keyCode, int metaState) {
111c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        Intent intent = null;
1121f2451007c660091b7b090c1ea332f9044515d2dJeff Brown
113c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        // First try the exact keycode (with modifiers).
114c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        int shortcut = kcm.get(keyCode, metaState);
115c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        if (shortcut != 0) {
116c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown            intent = mShortcutIntents.get(shortcut);
117c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        }
118c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown
119c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        // Next try the primary character on that key.
120c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        if (intent == null) {
121c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown            shortcut = Character.toLowerCase(kcm.getDisplayLabel(keyCode));
122c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown            if (shortcut != 0) {
123c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown                intent = mShortcutIntents.get(shortcut);
124c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown            }
125c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        }
126c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown
127c1fb48d77ce2db2ca3af1dd2eeb91dc1b0f81b46Jeff Brown        return intent;
1281f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project    }
1291f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project
1301f838aaece3cd61d07ab9e41c5c6af761d643324The Android Open Source Project}
131