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