summaryrefslogtreecommitdiffstats
path: root/src/com/android/launcher/Launcher.java
diff options
context:
space:
mode:
authorRomain Guy <romainguy@android.com>2009-06-09 12:57:21 -0700
committerRomain Guy <romainguy@android.com>2009-06-10 02:21:15 -0700
commit73b979d8c141c7ceac82dad7c5b271a6a42afa67 (patch)
tree1d73ba2b6d72282b116f2130b9f58536e46fd27f /src/com/android/launcher/Launcher.java
parentcbb89e4fc253a5fc3f24162dfb4e29fc6a815c2b (diff)
downloadandroid_packages_apps_Trebuchet-73b979d8c141c7ceac82dad7c5b271a6a42afa67.tar.gz
android_packages_apps_Trebuchet-73b979d8c141c7ceac82dad7c5b271a6a42afa67.tar.bz2
android_packages_apps_Trebuchet-73b979d8c141c7ceac82dad7c5b271a6a42afa67.zip
Add gestures to Home.
Press the Home key while in Home to enable the gestures pad.
Diffstat (limited to 'src/com/android/launcher/Launcher.java')
-rw-r--r--src/com/android/launcher/Launcher.java409
1 files changed, 368 insertions, 41 deletions
diff --git a/src/com/android/launcher/Launcher.java b/src/com/android/launcher/Launcher.java
index b4437d41d..0c54382dc 100644
--- a/src/com/android/launcher/Launcher.java
+++ b/src/com/android/launcher/Launcher.java
@@ -41,6 +41,8 @@ import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.Bitmap;
import android.graphics.Rect;
+import android.graphics.PorterDuffXfermode;
+import android.graphics.PorterDuff;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.TransitionDrawable;
@@ -58,7 +60,6 @@ import android.text.Selection;
import android.text.SpannableStringBuilder;
import android.text.TextUtils;
import android.text.method.TextKeyListener;
-import android.util.Log;
import static android.util.Log.*;
import android.view.Display;
import android.view.KeyEvent;
@@ -67,6 +68,8 @@ import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
+import android.view.MotionEvent;
+import android.view.Gravity;
import android.view.View.OnLongClickListener;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
@@ -74,8 +77,16 @@ import android.widget.GridView;
import android.widget.SlidingDrawer;
import android.widget.TextView;
import android.widget.Toast;
+import android.widget.ImageView;
+import android.widget.PopupWindow;
+import android.widget.ViewSwitcher;
import android.appwidget.AppWidgetManager;
import android.appwidget.AppWidgetProviderInfo;
+import android.gesture.GestureOverlayView;
+import android.gesture.GestureLibraries;
+import android.gesture.GestureLibrary;
+import android.gesture.Gesture;
+import android.gesture.Prediction;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
@@ -92,6 +103,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private static final boolean PROFILE_DRAWER = false;
private static final boolean PROFILE_ROTATE = false;
private static final boolean DEBUG_USER_INTERFACE = false;
+ private static final boolean DEBUG_GESTURES = false;
private static final int WALLPAPER_SCREENS_SPAN = 2;
@@ -100,7 +112,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private static final int MENU_WALLPAPER_SETTINGS = MENU_ADD + 1;
private static final int MENU_SEARCH = MENU_WALLPAPER_SETTINGS + 1;
private static final int MENU_NOTIFICATIONS = MENU_SEARCH + 1;
- private static final int MENU_SETTINGS = MENU_NOTIFICATIONS + 1;
+ private static final int MENU_GESTURES = MENU_NOTIFICATIONS + 1;
+ private static final int MENU_SETTINGS = MENU_GESTURES + 1;
private static final int REQUEST_CREATE_SHORTCUT = 1;
private static final int REQUEST_CREATE_LIVE_FOLDER = 4;
@@ -109,6 +122,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private static final int REQUEST_PICK_SHORTCUT = 7;
private static final int REQUEST_PICK_LIVE_FOLDER = 8;
private static final int REQUEST_PICK_APPWIDGET = 9;
+ private static final int REQUEST_PICK_GESTURE_ACTION = 10;
+ private static final int REQUEST_CREATE_GESTURE_ACTION = 11;
+ private static final int REQUEST_CREATE_GESTURE_APPLICATION_ACTION = 12;
static final String EXTRA_SHORTCUT_DUPLICATE = "duplicate";
@@ -154,6 +170,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME = "launcher.rename_folder";
// Type: long
private static final String RUNTIME_STATE_PENDING_FOLDER_RENAME_ID = "launcher.rename_folder_id";
+ // Type: Gesture (Parcelable)
+ private static final String RUNTIME_STATE_PENDING_GESTURE = "launcher.gesture";
private static final LauncherModel sModel = new LauncherModel();
@@ -164,6 +182,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private static WallpaperIntentReceiver sWallpaperReceiver;
+ private static GestureLibrary sLibrary;
+
private final BroadcastReceiver mApplicationsReceiver = new ApplicationsIntentReceiver();
private final ContentObserver mObserver = new FavoritesChangeObserver();
@@ -202,11 +222,26 @@ public final class Launcher extends Activity implements View.OnClickListener, On
private DesktopBinder mBinder;
+ private View mGesturesPanel;
+ private GestureOverlayView mGesturesOverlay;
+ private ViewSwitcher mGesturesPrompt;
+ private ImageView mGesturesAdd;
+ private PopupWindow mGesturesWindow;
+ private Launcher.GesturesProcessor mGesturesProcessor;
+ private Gesture mCurrentGesture;
+ private GesturesAction mGesturesAction;
+
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInflater = getLayoutInflater();
+ if (sLibrary == null) {
+ // The context is not kept by the library so it's safe to do this
+ sLibrary = GestureLibraries.fromPrivateFile(Launcher.this,
+ GesturesConstants.STORE_NAME);
+ }
+
mAppWidgetManager = AppWidgetManager.getInstance(this);
mAppWidgetHost = new LauncherAppWidgetHost(this, APPWIDGET_HOST_ID);
@@ -308,13 +343,17 @@ public final class Launcher extends Activity implements View.OnClickListener, On
// For example, the user would PICK_SHORTCUT for "Music playlist", and we
// launch over to the Music app to actually CREATE_SHORTCUT.
- if (resultCode == RESULT_OK && mAddItemCellInfo != null) {
+ if (resultCode == RESULT_OK && (mAddItemCellInfo != null ||
+ ((requestCode == REQUEST_PICK_GESTURE_ACTION ||
+ requestCode == REQUEST_CREATE_GESTURE_ACTION ||
+ requestCode == REQUEST_CREATE_GESTURE_APPLICATION_ACTION) && mCurrentGesture != null))) {
+
switch (requestCode) {
case REQUEST_PICK_APPLICATION:
completeAddApplication(this, data, mAddItemCellInfo, !mDesktopLocked);
break;
case REQUEST_PICK_SHORTCUT:
- addShortcut(data);
+ processShortcut(data, REQUEST_PICK_APPLICATION, REQUEST_CREATE_SHORTCUT);
break;
case REQUEST_CREATE_SHORTCUT:
completeAddShortcut(data, mAddItemCellInfo, !mDesktopLocked);
@@ -331,6 +370,16 @@ public final class Launcher extends Activity implements View.OnClickListener, On
case REQUEST_CREATE_APPWIDGET:
completeAddAppWidget(data, mAddItemCellInfo, !mDesktopLocked);
break;
+ case REQUEST_PICK_GESTURE_ACTION:
+ processShortcut(data, REQUEST_CREATE_GESTURE_APPLICATION_ACTION,
+ REQUEST_CREATE_GESTURE_ACTION);
+ break;
+ case REQUEST_CREATE_GESTURE_ACTION:
+ completeCreateGesture(data, true);
+ break;
+ case REQUEST_CREATE_GESTURE_APPLICATION_ACTION:
+ completeCreateGesture(data, false);
+ break;
}
} else if (requestCode == REQUEST_PICK_APPWIDGET &&
resultCode == RESULT_CANCELED && data != null) {
@@ -358,10 +407,20 @@ public final class Launcher extends Activity implements View.OnClickListener, On
@Override
protected void onPause() {
super.onPause();
+ if (mGesturesWindow != null) {
+ mGesturesWindow.setAnimationStyle(0);
+ mGesturesWindow.update();
+ }
closeDrawer(false);
}
@Override
+ protected void onStop() {
+ super.onStop();
+ hideGesturesPanel();
+ }
+
+ @Override
public Object onRetainNonConfigurationInstance() {
// Flag any binder to stop early before switching
if (mBinder != null) {
@@ -448,6 +507,8 @@ public final class Launcher extends Activity implements View.OnClickListener, On
mFolderInfo = sModel.getFolderById(this, id);
mRestoring = true;
}
+
+ mCurrentGesture = (Gesture) savedState.get(RUNTIME_STATE_PENDING_GESTURE);
}
/**
@@ -495,6 +556,68 @@ public final class Launcher extends Activity implements View.OnClickListener, On
dragLayer.setIgnoredDropTarget(grid);
dragLayer.setDragScoller(workspace);
dragLayer.setDragListener(deleteZone);
+
+ mGesturesPanel = mInflater.inflate(R.layout.gestures, mDragLayer, false);
+ final View gesturesPanel = mGesturesPanel;
+
+ mGesturesPrompt = (ViewSwitcher) gesturesPanel.findViewById(R.id.gestures_actions);
+ mGesturesAction = new GesturesAction();
+
+ mGesturesPrompt.getChildAt(0).setOnClickListener(mGesturesAction);
+ mGesturesPrompt.getChildAt(1).setOnClickListener(mGesturesAction);
+
+ mGesturesAdd = (ImageView) gesturesPanel.findViewById(R.id.gestures_add);
+ final ImageView gesturesAdd = mGesturesAdd;
+ gesturesAdd.setAlpha(128);
+ gesturesAdd.setEnabled(false);
+ gesturesAdd.setOnClickListener(new View.OnClickListener() {
+ public void onClick(View v) {
+ createGesture();
+ }
+ });
+
+ mGesturesOverlay = (GestureOverlayView) gesturesPanel.findViewById(R.id.gestures_overlay);
+ mGesturesProcessor = new GesturesProcessor();
+
+ final GestureOverlayView overlay = mGesturesOverlay;
+ overlay.setFadeOffset(GesturesConstants.MATCH_DELAY);
+ overlay.addOnGestureListener(mGesturesProcessor);
+ overlay.getGesturePaint().setXfermode(new PorterDuffXfermode(PorterDuff.Mode.MULTIPLY));
+ }
+
+ private void createGesture() {
+ mCurrentGesture = mGesturesOverlay.getGesture();
+ mWaitingForResult = true;
+ pickShortcut(REQUEST_PICK_GESTURE_ACTION, R.string.title_select_shortcut);
+ }
+
+ private void completeCreateGesture(Intent data, boolean isShortcut) {
+ ApplicationInfo info;
+
+ if (isShortcut) {
+ info = infoFromShortcutIntent(this, data);
+ } else {
+ info = infoFromApplicationIntent(this, data);
+ }
+
+ boolean success = false;
+ if (info != null) {
+ info.isGesture = true;
+
+ if (LauncherModel.addGestureToDatabase(this, info, false)) {
+ mGesturesProcessor.addGesture(String.valueOf(info.id), mCurrentGesture);
+ mGesturesProcessor.update(info, mCurrentGesture);
+ Toast.makeText(this, getString(R.string.gestures_created, info.title),
+ Toast.LENGTH_SHORT).show();
+ success = true;
+ }
+ }
+
+ if (!success) {
+ Toast.makeText(this, getString(R.string.gestures_failed), Toast.LENGTH_SHORT).show();
+ }
+
+ mCurrentGesture = null;
}
/**
@@ -545,14 +668,20 @@ public final class Launcher extends Activity implements View.OnClickListener, On
cellInfo.screen = mWorkspace.getCurrentScreen();
if (!findSingleSlot(cellInfo)) return;
- // Find details for this application
+ final ApplicationInfo info = infoFromApplicationIntent(context, data);
+ if (info != null) {
+ mWorkspace.addApplicationShortcut(info, cellInfo, insertAtFirst);
+ }
+ }
+
+ private static ApplicationInfo infoFromApplicationIntent(Context context, Intent data) {
ComponentName component = data.getComponent();
PackageManager packageManager = context.getPackageManager();
ActivityInfo activityInfo = null;
try {
activityInfo = packageManager.getActivityInfo(component, 0 /* no flags */);
} catch (NameNotFoundException e) {
- Log.e(LOG_TAG, "Couldn't find ActivityInfo for selected application", e);
+ e(LOG_TAG, "Couldn't find ActivityInfo for selected application", e);
}
if (activityInfo != null) {
@@ -568,8 +697,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On
itemInfo.icon = activityInfo.loadIcon(packageManager);
itemInfo.container = ItemInfo.NO_ID;
- mWorkspace.addApplicationShortcut(itemInfo, cellInfo, insertAtFirst);
+ return itemInfo;
}
+
+ return null;
}
/**
@@ -653,6 +784,14 @@ public final class Launcher extends Activity implements View.OnClickListener, On
static ApplicationInfo addShortcut(Context context, Intent data,
CellLayout.CellInfo cellInfo, boolean notify) {
+ final ApplicationInfo info = infoFromShortcutIntent(context, data);
+ LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
+ cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
+
+ return info;
+ }
+
+ private static ApplicationInfo infoFromShortcutIntent(Context context, Intent data) {
Intent intent = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_INTENT);
String name = data.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
Bitmap bitmap = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON);
@@ -660,7 +799,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
Drawable icon = null;
boolean filtered = false;
boolean customIcon = false;
- Intent.ShortcutIconResource iconResource = null;
+ ShortcutIconResource iconResource = null;
if (bitmap != null) {
icon = new FastBitmapDrawable(Utilities.createBitmapThumbnail(bitmap, context));
@@ -668,9 +807,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On
customIcon = true;
} else {
Parcelable extra = data.getParcelableExtra(Intent.EXTRA_SHORTCUT_ICON_RESOURCE);
- if (extra != null && extra instanceof Intent.ShortcutIconResource) {
+ if (extra != null && extra instanceof ShortcutIconResource) {
try {
- iconResource = (Intent.ShortcutIconResource) extra;
+ iconResource = (ShortcutIconResource) extra;
final PackageManager packageManager = context.getPackageManager();
Resources resources = packageManager.getResourcesForApplication(
iconResource.packageName);
@@ -694,8 +833,6 @@ public final class Launcher extends Activity implements View.OnClickListener, On
info.customIcon = customIcon;
info.iconResource = iconResource;
- LauncherModel.addItemToDatabase(context, info, LauncherSettings.Favorites.CONTAINER_DESKTOP,
- cellInfo.screen, cellInfo.cellX, cellInfo.cellY, notify);
return info;
}
@@ -723,15 +860,15 @@ public final class Launcher extends Activity implements View.OnClickListener, On
// An exception is thrown if the dialog is not visible, which is fine
}
- // If we are already in front we go back to the default screen,
- // otherwise we don't
if ((intent.getFlags() & Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) !=
Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT) {
- if (!mWorkspace.isDefaultScreenShowing()) {
- mWorkspace.moveToDefaultScreen();
+
+ if (mGesturesPanel != null && mDragLayer.getWindowVisibility() == View.VISIBLE) {
+ onHomeKeyPressed();
}
closeDrawer();
- View v = getWindow().peekDecorView();
+
+ final View v = getWindow().peekDecorView();
if (v != null && v.getWindowToken() != null) {
InputMethodManager imm = (InputMethodManager)getSystemService(
INPUT_METHOD_SERVICE);
@@ -743,6 +880,74 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
}
+ private void onHomeKeyPressed() {
+ if (mGesturesWindow == null || !mGesturesWindow.isShowing()) {
+ showGesturesPanel();
+ } else {
+ hideGesturesPanel();
+ }
+ }
+
+ private void showGesturesPanel() {
+ resetGesturesPrompt();
+
+ mGesturesAdd.setEnabled(false);
+ mGesturesAdd.setAlpha(128);
+
+ mGesturesOverlay.clear(false);
+
+ PopupWindow window;
+ if (mGesturesWindow == null) {
+ mGesturesWindow = new PopupWindow(this);
+ window = mGesturesWindow;
+ window.setFocusable(true);
+ window.setTouchable(true);
+ window.setBackgroundDrawable(null);
+ window.setContentView(mGesturesPanel);
+ } else {
+ window = mGesturesWindow;
+ }
+ window.setAnimationStyle(com.android.internal.R.style.Animation_SlidingCard);
+
+ final int[] xy = new int[2];
+ final DragLayer dragLayer = mDragLayer;
+ dragLayer.getLocationOnScreen(xy);
+
+ window.setWidth(dragLayer.getWidth());
+ window.setHeight(dragLayer.getHeight() - 1);
+ window.showAtLocation(dragLayer, Gravity.TOP | Gravity.LEFT, xy[0], xy[1] + 1);
+ }
+
+ private void resetGesturesPrompt() {
+ mGesturesAction.intent = null;
+ final TextView prompt = (TextView) mGesturesPrompt.getCurrentView();
+ prompt.setText(R.string.gestures_instructions);
+ prompt.setCompoundDrawablesWithIntrinsicBounds(null, null, null, null);
+ prompt.setClickable(false);
+ }
+
+ private void resetGesturesNextPrompt() {
+ mGesturesAction.intent = null;
+ setGesturesNextPrompt(null, getString(R.string.gestures_instructions));
+ mGesturesPrompt.getNextView().setClickable(false);
+ }
+
+ private void setGesturesNextPrompt(Drawable icon, CharSequence title) {
+ final TextView prompt = (TextView) mGesturesPrompt.getNextView();
+ prompt.setText(title);
+ prompt.setCompoundDrawablesWithIntrinsicBounds(icon, null, null, null);
+ prompt.setClickable(true);
+ mGesturesPrompt.showNext();
+ }
+
+ void hideGesturesPanel() {
+ if (mGesturesWindow != null) {
+ mGesturesWindow.setAnimationStyle(com.android.internal.R.style.Animation_SlidingCard);
+ mGesturesWindow.update();
+ mGesturesWindow.dismiss();
+ }
+ }
+
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
// Do not call super here
@@ -791,6 +996,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On
outState.putBoolean(RUNTIME_STATE_PENDING_FOLDER_RENAME, true);
outState.putLong(RUNTIME_STATE_PENDING_FOLDER_RENAME_ID, mFolderInfo.id);
}
+
+ if (mCurrentGesture != null && mWaitingForResult) {
+ outState.putParcelable(RUNTIME_STATE_PENDING_GESTURE, mCurrentGesture);
+ }
}
@Override
@@ -911,6 +1120,11 @@ public final class Launcher extends Activity implements View.OnClickListener, On
.setIcon(com.android.internal.R.drawable.ic_menu_notifications)
.setAlphabeticShortcut('N');
+ final Intent gestures = new Intent(this, GesturesActivity.class);
+ menu.add(0, MENU_GESTURES, 0, R.string.menu_gestures)
+ .setIcon(com.android.internal.R.drawable.ic_menu_compose).setAlphabeticShortcut('G')
+ .setIntent(gestures);
+
final Intent settings = new Intent(android.provider.Settings.ACTION_SETTINGS);
settings.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED);
@@ -1028,7 +1242,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
mWorkspace.addInCurrentScreen(view, xy[0], xy[1], info.spanX, spanY);
}
- void addShortcut(Intent intent) {
+ void processShortcut(Intent intent, int requestCodeApplication, int requestCodeShortcut) {
// Handle case where user selected "Applications"
String applicationName = getResources().getString(R.string.group_applications);
String shortcutName = intent.getStringExtra(Intent.EXTRA_SHORTCUT_NAME);
@@ -1039,9 +1253,9 @@ public final class Launcher extends Activity implements View.OnClickListener, On
Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
pickIntent.putExtra(Intent.EXTRA_INTENT, mainIntent);
- startActivityForResult(pickIntent, REQUEST_PICK_APPLICATION);
+ startActivityForResult(pickIntent, requestCodeApplication);
} else {
- startActivityForResult(intent, REQUEST_CREATE_SHORTCUT);
+ startActivityForResult(intent, requestCodeShortcut);
}
}
@@ -1482,7 +1696,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
} catch (SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT).show();
- Log.e(LOG_TAG, "Launcher does not have the permission to launch " + intent +
+ e(LOG_TAG, "Launcher does not have the permission to launch " + intent +
". Make sure to create a MAIN intent-filter for the corresponding activity " +
"or use the exported attribute for this activity.", e);
}
@@ -1601,6 +1815,10 @@ public final class Launcher extends Activity implements View.OnClickListener, On
return sModel;
}
+ static GestureLibrary getGestureLibrary() {
+ return sLibrary;
+ }
+
void closeAllApplications() {
mDrawer.close();
}
@@ -1669,6 +1887,26 @@ public final class Launcher extends Activity implements View.OnClickListener, On
showDialog(DIALOG_CREATE_SHORTCUT);
}
+ private void pickShortcut(int requestCode, int title) {
+ Bundle bundle = new Bundle();
+
+ ArrayList<String> shortcutNames = new ArrayList<String>();
+ shortcutNames.add(getString(R.string.group_applications));
+ bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
+
+ ArrayList<ShortcutIconResource> shortcutIcons = new ArrayList<ShortcutIconResource>();
+ shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
+ R.drawable.ic_launcher_application));
+ bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
+
+ Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
+ pickIntent.putExtra(Intent.EXTRA_INTENT, new Intent(Intent.ACTION_CREATE_SHORTCUT));
+ pickIntent.putExtra(Intent.EXTRA_TITLE, getText(title));
+ pickIntent.putExtras(bundle);
+
+ startActivityForResult(pickIntent, requestCode);
+ }
+
private class RenameFolder {
private EditText mInput;
@@ -1789,26 +2027,7 @@ public final class Launcher extends Activity implements View.OnClickListener, On
switch (which) {
case AddAdapter.ITEM_SHORTCUT: {
// Insert extra item to handle picking application
- Bundle bundle = new Bundle();
-
- ArrayList<String> shortcutNames = new ArrayList<String>();
- shortcutNames.add(res.getString(R.string.group_applications));
- bundle.putStringArrayList(Intent.EXTRA_SHORTCUT_NAME, shortcutNames);
-
- ArrayList<ShortcutIconResource> shortcutIcons =
- new ArrayList<ShortcutIconResource>();
- shortcutIcons.add(ShortcutIconResource.fromContext(Launcher.this,
- R.drawable.ic_launcher_application));
- bundle.putParcelableArrayList(Intent.EXTRA_SHORTCUT_ICON_RESOURCE, shortcutIcons);
-
- Intent pickIntent = new Intent(Intent.ACTION_PICK_ACTIVITY);
- pickIntent.putExtra(Intent.EXTRA_INTENT,
- new Intent(Intent.ACTION_CREATE_SHORTCUT));
- pickIntent.putExtra(Intent.EXTRA_TITLE,
- getText(R.string.title_select_shortcut));
- pickIntent.putExtras(bundle);
-
- startActivityForResult(pickIntent, REQUEST_PICK_SHORTCUT);
+ pickShortcut(REQUEST_PICK_SHORTCUT, R.string.title_select_shortcut);
break;
}
@@ -2109,5 +2328,113 @@ public final class Launcher extends Activity implements View.OnClickListener, On
}
}
}
+
+ private class GesturesProcessor implements GestureOverlayView.OnGestureListener,
+ GestureOverlayView.OnGesturePerformedListener {
+
+ private final GestureMatcher mMatcher = new GestureMatcher();
+
+ GesturesProcessor() {
+ // TODO: Maybe the load should happen on a background thread?
+ sLibrary.load();
+ }
+
+ public void onGestureStarted(GestureOverlayView overlay, MotionEvent event) {
+ overlay.removeCallbacks(mMatcher);
+ resetGesturesNextPrompt();
+
+ mGesturesAdd.setAlpha(128);
+ mGesturesAdd.setEnabled(false);
+ }
+
+ public void onGesture(GestureOverlayView overlay, MotionEvent event) {
+ }
+
+ public void onGesturePerformed(GestureOverlayView overlay, Gesture gesture) {
+ }
+
+ public void onGestureEnded(GestureOverlayView overlay, MotionEvent event) {
+ overlay.removeCallbacks(mMatcher);
+
+ mMatcher.gesture = overlay.getGesture();
+ if (mMatcher.gesture.getLength() < GesturesConstants.LENGTH_THRESHOLD) {
+ overlay.clear(false);
+ } else {
+ overlay.postDelayed(mMatcher, GesturesConstants.MATCH_DELAY);
+ }
+ }
+
+ private void matchGesture(Gesture gesture) {
+ mGesturesAdd.setAlpha(255);
+ mGesturesAdd.setEnabled(true);
+
+ if (gesture != null) {
+ final ArrayList<Prediction> predictions = sLibrary.recognize(gesture);
+
+ if (DEBUG_GESTURES) {
+ for (Prediction p : predictions) {
+ d(LOG_TAG, String.format("name=%s, score=%f", p.name, p.score));
+ }
+ }
+
+ boolean match = false;
+ if (predictions.size() > 0) {
+ final Prediction prediction = predictions.get(0);
+ if (prediction.score > GesturesConstants.PREDICTION_THRESHOLD) {
+ match = true;
+
+ ApplicationInfo info = sModel.queryGesture(Launcher.this, prediction.name);
+ if (info != null) {
+ updatePrompt(info);
+ }
+ }
+ }
+
+ if (!match){
+ setGesturesNextPrompt(null, getString(R.string.gestures_unknown));
+ }
+ }
+ }
+
+ private void updatePrompt(ApplicationInfo info) {
+ setGesturesNextPrompt(info.icon, info.title);
+ mGesturesAction.intent = info.intent;
+ }
+
+ public void onGestureCancelled(GestureOverlayView overlay, MotionEvent event) {
+ overlay.removeCallbacks(mMatcher);
+ }
+
+ void addGesture(String name, Gesture gesture) {
+ sLibrary.addGesture(name, gesture);
+ // TODO: On a background thread?
+ sLibrary.save();
+ }
+
+ void update(ApplicationInfo info, Gesture gesture) {
+ mGesturesOverlay.setGesture(gesture);
+ updatePrompt(info);
+ }
+
+ class GestureMatcher implements Runnable {
+ Gesture gesture;
+
+ public void run() {
+ if (gesture != null) {
+ matchGesture(gesture);
+ }
+ }
+ }
+ }
+
+ private class GesturesAction implements View.OnClickListener {
+ Intent intent;
+
+ public void onClick(View v) {
+ if (intent != null) {
+ startActivitySafely(intent);
+ }
+ }
+ }
}