Add gestures to Home.
Press the Home key while in Home to enable the gestures pad.
@@ -91,6 +91,10 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
|
||||
<activity
|
||||
android:name="GesturesActivity"
|
||||
android:label="@string/gestures_activity" />
|
||||
|
||||
<!-- Enable system-default search mode for any activity in Home -->
|
||||
<meta-data
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
|
||||
android:fromAlpha="0.0"
|
||||
android:toAlpha="1.0"
|
||||
|
||||
android:duration="@android:integer/config_mediumAnimTime" />
|
||||
@@ -0,0 +1,23 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<alpha xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:interpolator="@android:anim/accelerate_interpolator"
|
||||
|
||||
android:fromAlpha="1.0"
|
||||
android:toAlpha="0.0"
|
||||
|
||||
android:duration="@android:integer/config_mediumAnimTime" />
|
||||
@@ -0,0 +1,32 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<selector xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<item android:state_window_focused="false" android:state_enabled="true"
|
||||
android:drawable="@drawable/btn_circle_normal" />
|
||||
<item android:state_window_focused="false" android:state_enabled="false"
|
||||
android:drawable="@drawable/btn_circle_disable" />
|
||||
<item android:state_pressed="true"
|
||||
android:drawable="@drawable/btn_circle_pressed" />
|
||||
<item android:state_focused="true" android:state_enabled="true"
|
||||
android:drawable="@drawable/btn_circle_selected" />
|
||||
<item android:state_enabled="true"
|
||||
android:drawable="@drawable/btn_circle_normal" />
|
||||
<item android:state_focused="true"
|
||||
android:drawable="@drawable/btn_circle_disable_focused" />
|
||||
<item
|
||||
android:drawable="@drawable/btn_circle_disable" />
|
||||
</selector>
|
||||
|
After Width: | Height: | Size: 938 B |
|
After Width: | Height: | Size: 1.4 KiB |
|
After Width: | Height: | Size: 1.2 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
|
After Width: | Height: | Size: 1.6 KiB |
@@ -0,0 +1,20 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2009 Romain Guy
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:src="@drawable/texture_paper"
|
||||
android:tileMode="repeat" />
|
||||
|
After Width: | Height: | Size: 526 B |
|
After Width: | Height: | Size: 989 B |
@@ -0,0 +1,96 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<!-- Note: GesturesPanel is a special implementation that forces the widget
|
||||
to be opaque for performance reasons. Make sure it visually is. -->
|
||||
<com.android.launcher.GesturesPanel
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
|
||||
android:id="@+id/gestures_panel"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ViewSwitcher
|
||||
android:id="@+id/gestures_actions"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="83dip"
|
||||
android:layout_alignParentBottom="true"
|
||||
|
||||
android:inAnimation="@anim/fade_in_fast"
|
||||
android:outAnimation="@anim/fade_out_fast"
|
||||
|
||||
android:foregroundGravity="top|fill_horizontal"
|
||||
android:foreground="@*android:drawable/title_bar_shadow"
|
||||
android:background="@android:drawable/title_bar_tall">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
||||
android:gravity="center_vertical"
|
||||
|
||||
android:shadowColor="#FF000000"
|
||||
android:shadowRadius="2.0"
|
||||
|
||||
android:drawablePadding="6dip"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:text="@string/gestures_instructions" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_gravity="center_horizontal"
|
||||
|
||||
android:gravity="center_vertical"
|
||||
|
||||
android:shadowColor="#FF000000"
|
||||
android:shadowRadius="2.0"
|
||||
|
||||
android:drawablePadding="6dip"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
||||
android:ellipsize="end"
|
||||
android:maxLines="2"
|
||||
android:text="@string/gestures_instructions" />
|
||||
|
||||
</ViewSwitcher>
|
||||
|
||||
<android.gesture.GestureOverlayView
|
||||
android:id="@+id/gestures_overlay"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="0dip"
|
||||
android:layout_weight="1.0"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_above="@id/gestures_actions"
|
||||
|
||||
android:background="@drawable/gestures_background"
|
||||
|
||||
android:gestureStrokeType="multiple" />
|
||||
|
||||
<ImageButton
|
||||
style="@style/PlusButton"
|
||||
|
||||
android:id="@+id/gestures_add"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentRight="true"
|
||||
android:layout_alignTop="@id/gestures_actions"
|
||||
android:layout_marginRight="10dip"
|
||||
android:layout_marginTop="-22dip" />
|
||||
|
||||
</com.android.launcher.GesturesPanel>
|
||||
@@ -0,0 +1,37 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent">
|
||||
|
||||
<ListView
|
||||
android:id="@android:id/list"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent" />
|
||||
|
||||
<TextView
|
||||
android:id="@android:id/empty"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_vertical"
|
||||
|
||||
android:gravity="center_horizontal"
|
||||
|
||||
android:text="@string/gestures_loading"
|
||||
android:textAppearance="?android:attr/textAppearanceMedium" />
|
||||
|
||||
</FrameLayout>
|
||||
@@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2009 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@android:id/text1"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
|
||||
android:gravity="center_vertical"
|
||||
android:minHeight="?android:attr/listPreferredItemHeight"
|
||||
|
||||
android:drawablePadding="12dip"
|
||||
android:paddingLeft="6dip"
|
||||
android:paddingRight="2dip"
|
||||
|
||||
android:ellipsize="marquee"
|
||||
android:singleLine="true"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
@@ -21,6 +21,7 @@
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/label"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:text="@string/rename_folder_label"
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
<color name="bubble_dark_background">#B2191919</color>
|
||||
<color name="delete_color_filter">#A5FF0000</color>
|
||||
|
||||
<color name="appwidget_error_color">#fccc</color>
|
||||
<color name="snag_callout_color">#f444</color>
|
||||
<color name="appwidget_error_color">#FCCC</color>
|
||||
<color name="snag_callout_color">#F444</color>
|
||||
|
||||
<color name="gesture_color">#FFFFFF00</color>
|
||||
</resources>
|
||||
|
||||
@@ -16,4 +16,6 @@
|
||||
|
||||
<resources>
|
||||
<dimen name="search_widget_inset">19dip</dimen>
|
||||
<dimen name="gesture_thumbnail_inset">8dip</dimen>
|
||||
<dimen name="gesture_thumbnail_size">64dip</dimen>
|
||||
</resources>
|
||||
|
||||
@@ -94,7 +94,9 @@
|
||||
<string name="menu_search">Search</string>
|
||||
<!-- Noun, menu item used to bring down the notifications shade -->
|
||||
<string name="menu_notifications">Notifications</string>
|
||||
<!-- Noun, menu item used to show the system settings -->
|
||||
<!-- Noun, menu item used to show the gestures settings -->
|
||||
<string name="menu_gestures">Gestures</string>
|
||||
<!-- Noun, menu item used to show the system settings -->
|
||||
<string name="menu_settings">Settings</string>
|
||||
|
||||
<!-- Permissions: -->
|
||||
@@ -123,4 +125,31 @@
|
||||
<!-- Text to show user in place of a gadget when we can't display it properly -->
|
||||
<string name="gadget_error_text">Problem loading widget</string>
|
||||
|
||||
<!-- Gestures: -->
|
||||
<skip />
|
||||
|
||||
<!-- Message displayed when the user enters gestures mode and is asked to draw a gesture -->
|
||||
<string name="gestures_instructions">Draw a gesture to get started</string>
|
||||
<!-- Message displayed when the gesture entered by the user cannot be recognized -->
|
||||
<string name="gestures_unknown">Unknown gesture</string>
|
||||
<!-- Message displayed when the user has successfully created a new gesture -->
|
||||
<string name="gestures_created">Added gesture "%s"</string>
|
||||
<!-- Message displayed when the user could not create a new gesture -->
|
||||
<string name="gestures_failed">Gesture could not be created</string>
|
||||
<!-- Message displayed when the user opens the gestures settings screen -->
|
||||
<string name="gestures_loading">Loading gestures...</string>
|
||||
<!-- Message displayed when the user has no gestures -->
|
||||
<string name="gestures_empty">No gestures defined</string>
|
||||
<!-- Title of the screen used to view/manage gestures -->
|
||||
<string name="gestures_activity">Gestures</string>
|
||||
<!-- Noun, menu item used to rename a gesture -->
|
||||
<string name="gestures_rename">Rename</string>
|
||||
<!-- Noun, menu item used to remove a gesture -->
|
||||
<string name="gestures_delete">Delete</string>
|
||||
<!-- Message displayed when a gesture is successfully deleted -->
|
||||
<string name="gestures_delete_success">Gesture deleted</string>
|
||||
<!-- Title of dialog box -->
|
||||
<string name="gestures_rename_title">Rename gesture</string>
|
||||
<!-- Label of gesture name field in Rename gesture dialog box -->
|
||||
<string name="gestures_rename_label">Gesture name</string>
|
||||
</resources>
|
||||
|
||||
@@ -60,4 +60,10 @@
|
||||
<item name="android:paddingLeft">10dip</item>
|
||||
<item name="android:paddingRight">10dip</item>
|
||||
</style>
|
||||
|
||||
<style name="PlusButton">
|
||||
<item name="android:background">@drawable/btn_circle</item>
|
||||
<item name="android:src">@drawable/ic_btn_round_plus</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
||||
@@ -61,7 +61,7 @@ class ApplicationInfo extends ItemInfo {
|
||||
Intent.ShortcutIconResource iconResource;
|
||||
|
||||
ApplicationInfo() {
|
||||
itemType = LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT;
|
||||
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_SHORTCUT;
|
||||
}
|
||||
|
||||
public ApplicationInfo(ApplicationInfo info) {
|
||||
@@ -80,7 +80,7 @@ class ApplicationInfo extends ItemInfo {
|
||||
|
||||
/**
|
||||
* Creates the application intent based on a component name and various launch flags.
|
||||
* Sets {@link #itemType} to {@link LauncherSettings.Favorites#ITEM_TYPE_APPLICATION}.
|
||||
* Sets {@link #itemType} to {@link LauncherSettings.BaseLauncherColumns#ITEM_TYPE_APPLICATION}.
|
||||
*
|
||||
* @param className the class name of the component representing the intent
|
||||
* @param launchFlags the launch flags
|
||||
@@ -90,7 +90,7 @@ class ApplicationInfo extends ItemInfo {
|
||||
intent.addCategory(Intent.CATEGORY_LAUNCHER);
|
||||
intent.setComponent(className);
|
||||
intent.setFlags(launchFlags);
|
||||
itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION;
|
||||
itemType = LauncherSettings.BaseLauncherColumns.ITEM_TYPE_APPLICATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -98,22 +98,24 @@ class ApplicationInfo extends ItemInfo {
|
||||
super.onAddToDatabase(values);
|
||||
|
||||
String titleStr = title != null ? title.toString() : null;
|
||||
values.put(LauncherSettings.Favorites.TITLE, titleStr);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.TITLE, titleStr);
|
||||
|
||||
String uri = intent != null ? intent.toURI() : null;
|
||||
values.put(LauncherSettings.Favorites.INTENT, uri);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.INTENT, uri);
|
||||
|
||||
if (customIcon) {
|
||||
values.put(LauncherSettings.Favorites.ICON_TYPE,
|
||||
LauncherSettings.Favorites.ICON_TYPE_BITMAP);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
|
||||
LauncherSettings.BaseLauncherColumns.ICON_TYPE_BITMAP);
|
||||
Bitmap bitmap = ((FastBitmapDrawable) icon).getBitmap();
|
||||
writeBitmap(values, bitmap);
|
||||
} else {
|
||||
values.put(LauncherSettings.Favorites.ICON_TYPE,
|
||||
LauncherSettings.Favorites.ICON_TYPE_RESOURCE);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_TYPE,
|
||||
LauncherSettings.BaseLauncherColumns.ICON_TYPE_RESOURCE);
|
||||
if (iconResource != null) {
|
||||
values.put(LauncherSettings.Favorites.ICON_PACKAGE, iconResource.packageName);
|
||||
values.put(LauncherSettings.Favorites.ICON_RESOURCE, iconResource.resourceName);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_PACKAGE,
|
||||
iconResource.packageName);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ICON_RESOURCE,
|
||||
iconResource.resourceName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,310 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.app.Dialog;
|
||||
import android.app.AlertDialog;
|
||||
import android.os.Bundle;
|
||||
import android.os.AsyncTask;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.TextView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.Toast;
|
||||
import android.widget.EditText;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.res.Resources;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.ContextMenu;
|
||||
import android.view.MenuItem;
|
||||
import android.gesture.GestureLibrary;
|
||||
import android.gesture.Gesture;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.text.TextUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.HashMap;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
|
||||
public class GesturesActivity extends ListActivity {
|
||||
private static final int MENU_ID_RENAME = 1;
|
||||
private static final int MENU_ID_REMOVE = 2;
|
||||
|
||||
private static final int DIALOG_RENAME_GESTURE = 1;
|
||||
|
||||
private final Comparator<ApplicationInfo> mSorter =
|
||||
new LauncherModel.ApplicationInfoComparator();
|
||||
|
||||
private GesturesAdapter mAdapter;
|
||||
private GestureLibrary mStore;
|
||||
private GesturesLoadTask mTask;
|
||||
private TextView mEmpty;
|
||||
|
||||
private Dialog mRenameDialog;
|
||||
private EditText mInput;
|
||||
private ApplicationInfo mCurrentRenameInfo;
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
|
||||
setContentView(R.layout.gestures_settings);
|
||||
|
||||
mAdapter = new GesturesAdapter(this);
|
||||
setListAdapter(mAdapter);
|
||||
|
||||
mStore = Launcher.getGestureLibrary();
|
||||
mEmpty = (TextView) findViewById(android.R.id.empty);
|
||||
mTask = (GesturesLoadTask) new GesturesLoadTask().execute();
|
||||
|
||||
registerForContextMenu(getListView());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
|
||||
if (mTask != null && mTask.getStatus() != GesturesLoadTask.Status.FINISHED) {
|
||||
mTask.cancel(true);
|
||||
mTask = null;
|
||||
}
|
||||
|
||||
cleanupRenameDialog();
|
||||
}
|
||||
|
||||
private void checkForEmpty() {
|
||||
if (mAdapter.getCount() == 0) {
|
||||
mEmpty.setText(R.string.gestures_empty);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateContextMenu(ContextMenu menu, View v,
|
||||
ContextMenu.ContextMenuInfo menuInfo) {
|
||||
|
||||
super.onCreateContextMenu(menu, v, menuInfo);
|
||||
|
||||
AdapterView.AdapterContextMenuInfo info = (AdapterView.AdapterContextMenuInfo) menuInfo;
|
||||
menu.setHeaderTitle(((TextView) info.targetView).getText());
|
||||
|
||||
menu.add(0, MENU_ID_RENAME, 0, R.string.gestures_rename);
|
||||
menu.add(0, MENU_ID_REMOVE, 0, R.string.gestures_delete);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onContextItemSelected(MenuItem item) {
|
||||
final AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo)
|
||||
item.getMenuInfo();
|
||||
final ApplicationInfo info = (ApplicationInfo) menuInfo.targetView.getTag();
|
||||
|
||||
switch (item.getItemId()) {
|
||||
case MENU_ID_RENAME:
|
||||
renameGesture(info);
|
||||
return true;
|
||||
case MENU_ID_REMOVE:
|
||||
deleteGesture(info);
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.onContextItemSelected(item);
|
||||
}
|
||||
|
||||
private void renameGesture(ApplicationInfo info) {
|
||||
mCurrentRenameInfo = info;
|
||||
showDialog(DIALOG_RENAME_GESTURE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Dialog onCreateDialog(int id) {
|
||||
if (id == DIALOG_RENAME_GESTURE) {
|
||||
return createRenameDialog();
|
||||
}
|
||||
return super.onCreateDialog(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPrepareDialog(int id, Dialog dialog) {
|
||||
super.onPrepareDialog(id, dialog);
|
||||
if (id == DIALOG_RENAME_GESTURE) {
|
||||
mInput.setText(mCurrentRenameInfo.title);
|
||||
}
|
||||
}
|
||||
|
||||
private Dialog createRenameDialog() {
|
||||
final View layout = View.inflate(this, R.layout.rename_folder, null);
|
||||
mInput = (EditText) layout.findViewById(R.id.folder_name);
|
||||
((TextView) layout.findViewById(R.id.label)).setText(R.string.gestures_rename_label);
|
||||
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(this);
|
||||
builder.setIcon(0);
|
||||
builder.setTitle(getString(R.string.gestures_rename_title));
|
||||
builder.setCancelable(true);
|
||||
builder.setOnCancelListener(new Dialog.OnCancelListener() {
|
||||
public void onCancel(DialogInterface dialog) {
|
||||
cleanupRenameDialog();
|
||||
}
|
||||
});
|
||||
builder.setNegativeButton(getString(R.string.cancel_action),
|
||||
new Dialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
cleanupRenameDialog();
|
||||
}
|
||||
}
|
||||
);
|
||||
builder.setPositiveButton(getString(R.string.rename_action),
|
||||
new Dialog.OnClickListener() {
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
changeGestureName();
|
||||
}
|
||||
}
|
||||
);
|
||||
builder.setView(layout);
|
||||
return builder.create();
|
||||
}
|
||||
|
||||
private void changeGestureName() {
|
||||
final String name = mInput.getText().toString();
|
||||
if (!TextUtils.isEmpty(name)) {
|
||||
mCurrentRenameInfo.title = mInput.getText();
|
||||
LauncherModel.updateGestureInDatabase(this, mCurrentRenameInfo);
|
||||
}
|
||||
}
|
||||
|
||||
private void cleanupRenameDialog() {
|
||||
if (mRenameDialog != null) {
|
||||
mRenameDialog.dismiss();
|
||||
mRenameDialog = null;
|
||||
mInput = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void deleteGesture(ApplicationInfo info) {
|
||||
mStore.removeEntry(String.valueOf(info.id));
|
||||
// TODO: On a thread?
|
||||
mStore.save();
|
||||
|
||||
final GesturesActivity.GesturesAdapter adapter = mAdapter;
|
||||
adapter.setNotifyOnChange(false);
|
||||
adapter.remove(info);
|
||||
adapter.sort(mSorter);
|
||||
checkForEmpty();
|
||||
adapter.notifyDataSetChanged();
|
||||
|
||||
LauncherModel.deleteGestureFromDatabase(this, info);
|
||||
|
||||
Toast.makeText(this, R.string.gestures_delete_success, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
|
||||
private class GesturesLoadTask extends AsyncTask<Void, ApplicationInfo, Boolean> {
|
||||
private int mThumbnailSize;
|
||||
private int mThumbnailInset;
|
||||
private int mPathColor;
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
super.onPreExecute();
|
||||
|
||||
final Resources resources = getResources();
|
||||
mPathColor = resources.getColor(R.color.gesture_color);
|
||||
mThumbnailInset = (int) resources.getDimension(R.dimen.gesture_thumbnail_inset);
|
||||
mThumbnailSize = (int) resources.getDimension(R.dimen.gesture_thumbnail_size);
|
||||
}
|
||||
|
||||
protected Boolean doInBackground(Void... params) {
|
||||
if (isCancelled()) return Boolean.FALSE;
|
||||
|
||||
final GestureLibrary store = mStore;
|
||||
|
||||
if (store.load()) {
|
||||
final LauncherModel model = Launcher.getModel();
|
||||
|
||||
for (String name : store.getGestureEntries()) {
|
||||
final Gesture gesture = store.getGestures(name).get(0);
|
||||
final Bitmap bitmap = gesture.toBitmap(mThumbnailSize, mThumbnailSize,
|
||||
mThumbnailInset, mPathColor);
|
||||
final ApplicationInfo info = model.queryGesture(GesturesActivity.this, name);
|
||||
|
||||
mAdapter.addBitmap(info.id, bitmap);
|
||||
publishProgress(info);
|
||||
}
|
||||
|
||||
return Boolean.TRUE;
|
||||
}
|
||||
|
||||
return Boolean.FALSE;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onProgressUpdate(ApplicationInfo... values) {
|
||||
super.onProgressUpdate(values);
|
||||
|
||||
final GesturesActivity.GesturesAdapter adapter = mAdapter;
|
||||
adapter.setNotifyOnChange(false);
|
||||
|
||||
for (ApplicationInfo info : values) {
|
||||
adapter.add(info);
|
||||
}
|
||||
|
||||
adapter.sort(mSorter);
|
||||
adapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Boolean aBoolean) {
|
||||
super.onPostExecute(aBoolean);
|
||||
checkForEmpty();
|
||||
}
|
||||
}
|
||||
|
||||
private class GesturesAdapter extends ArrayAdapter<ApplicationInfo> {
|
||||
private final LayoutInflater mInflater;
|
||||
private final Map<Long, Drawable> mThumbnails = Collections.synchronizedMap(
|
||||
new HashMap<Long, Drawable>());
|
||||
|
||||
public GesturesAdapter(Context context) {
|
||||
super(context, 0);
|
||||
mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
|
||||
}
|
||||
|
||||
void addBitmap(Long id, Bitmap bitmap) {
|
||||
mThumbnails.put(id, new BitmapDrawable(bitmap));
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = mInflater.inflate(R.layout.gestures_settings_item, parent, false);
|
||||
}
|
||||
|
||||
final ApplicationInfo info = getItem(position);
|
||||
final TextView label = (TextView) convertView;
|
||||
|
||||
label.setTag(info);
|
||||
label.setText(info.title);
|
||||
label.setCompoundDrawablesWithIntrinsicBounds(info.icon, null,
|
||||
mThumbnails.get(info.id), null);
|
||||
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher;
|
||||
|
||||
interface GesturesConstants {
|
||||
final double PREDICTION_THRESHOLD = 1.0;
|
||||
final String STORE_NAME = "gestures";
|
||||
final long MATCH_DELAY = 370;
|
||||
final float LENGTH_THRESHOLD = 120.0f;
|
||||
int PATH_SAMPLE_COUNT = 10;
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.launcher;
|
||||
|
||||
import android.widget.RelativeLayout;
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
public class GesturesPanel extends RelativeLayout {
|
||||
public GesturesPanel(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
public GesturesPanel(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOpaque() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
|
||||
((Launcher) mContext).hideGesturesPanel();
|
||||
return true;
|
||||
}
|
||||
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
}
|
||||
@@ -76,6 +76,11 @@ class ItemInfo {
|
||||
*/
|
||||
int spanY = 1;
|
||||
|
||||
/**
|
||||
* Indicates whether the item is a gesture.
|
||||
*/
|
||||
boolean isGesture = false;
|
||||
|
||||
ItemInfo() {
|
||||
}
|
||||
|
||||
@@ -96,13 +101,15 @@ class ItemInfo {
|
||||
* @param values
|
||||
*/
|
||||
void onAddToDatabase(ContentValues values) {
|
||||
values.put(LauncherSettings.Favorites.ITEM_TYPE, itemType);
|
||||
values.put(LauncherSettings.Favorites.CONTAINER, container);
|
||||
values.put(LauncherSettings.Favorites.SCREEN, screen);
|
||||
values.put(LauncherSettings.Favorites.CELLX, cellX);
|
||||
values.put(LauncherSettings.Favorites.CELLY, cellY);
|
||||
values.put(LauncherSettings.Favorites.SPANX, spanX);
|
||||
values.put(LauncherSettings.Favorites.SPANY, spanY);
|
||||
values.put(LauncherSettings.BaseLauncherColumns.ITEM_TYPE, itemType);
|
||||
if (!isGesture) {
|
||||
values.put(LauncherSettings.Favorites.CONTAINER, container);
|
||||
values.put(LauncherSettings.Favorites.SCREEN, screen);
|
||||
values.put(LauncherSettings.Favorites.CELLX, cellX);
|
||||
values.put(LauncherSettings.Favorites.CELLY, cellY);
|
||||
values.put(LauncherSettings.Favorites.SPANX, spanX);
|
||||
values.put(LauncherSettings.Favorites.SPANY, spanY);
|
||||
}
|
||||
}
|
||||
|
||||
static void writeBitmap(ContentValues values, Bitmap bitmap) {
|
||||
|
||||
@@ -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,9 +407,19 @@ 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
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -560,7 +560,7 @@ public class LauncherModel {
|
||||
}
|
||||
}
|
||||
|
||||
private static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
|
||||
static class ApplicationInfoComparator implements Comparator<ApplicationInfo> {
|
||||
public final int compare(ApplicationInfo a, ApplicationInfo b) {
|
||||
return sCollator.compare(a.title.toString(), b.title.toString());
|
||||
}
|
||||
@@ -614,11 +614,11 @@ public class LauncherModel {
|
||||
|
||||
private static void updateShortcutLabels(ContentResolver resolver, PackageManager manager) {
|
||||
final Cursor c = resolver.query(LauncherSettings.Favorites.CONTENT_URI,
|
||||
new String[] { LauncherSettings.Favorites.ID, LauncherSettings.Favorites.TITLE,
|
||||
new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.TITLE,
|
||||
LauncherSettings.Favorites.INTENT, LauncherSettings.Favorites.ITEM_TYPE },
|
||||
null, null, null);
|
||||
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
|
||||
final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
|
||||
final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ITEM_TYPE);
|
||||
final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
|
||||
@@ -725,7 +725,7 @@ public class LauncherModel {
|
||||
LauncherSettings.Favorites.CONTENT_URI, null, null, null, null);
|
||||
|
||||
try {
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
|
||||
final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
|
||||
final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
|
||||
final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
|
||||
@@ -1143,7 +1143,7 @@ public class LauncherModel {
|
||||
/**
|
||||
* Make an ApplicationInfo object for a sortcut
|
||||
*/
|
||||
private ApplicationInfo getApplicationInfoShortcut(Cursor c, Launcher launcher,
|
||||
private ApplicationInfo getApplicationInfoShortcut(Cursor c, Context context,
|
||||
int iconTypeIndex, int iconPackageIndex, int iconResourceIndex, int iconIndex) {
|
||||
|
||||
final ApplicationInfo info = new ApplicationInfo();
|
||||
@@ -1154,11 +1154,11 @@ public class LauncherModel {
|
||||
case LauncherSettings.Favorites.ICON_TYPE_RESOURCE:
|
||||
String packageName = c.getString(iconPackageIndex);
|
||||
String resourceName = c.getString(iconResourceIndex);
|
||||
PackageManager packageManager = launcher.getPackageManager();
|
||||
PackageManager packageManager = context.getPackageManager();
|
||||
try {
|
||||
Resources resources = packageManager.getResourcesForApplication(packageName);
|
||||
final int id = resources.getIdentifier(resourceName, null, null);
|
||||
info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), launcher);
|
||||
info.icon = Utilities.createIconThumbnail(resources.getDrawable(id), context);
|
||||
} catch (Exception e) {
|
||||
info.icon = packageManager.getDefaultActivityIcon();
|
||||
}
|
||||
@@ -1172,16 +1172,16 @@ public class LauncherModel {
|
||||
try {
|
||||
Bitmap bitmap = BitmapFactory.decodeByteArray(data, 0, data.length);
|
||||
info.icon = new FastBitmapDrawable(
|
||||
Utilities.createBitmapThumbnail(bitmap, launcher));
|
||||
Utilities.createBitmapThumbnail(bitmap, context));
|
||||
} catch (Exception e) {
|
||||
packageManager = launcher.getPackageManager();
|
||||
packageManager = context.getPackageManager();
|
||||
info.icon = packageManager.getDefaultActivityIcon();
|
||||
}
|
||||
info.filtered = true;
|
||||
info.customIcon = true;
|
||||
break;
|
||||
default:
|
||||
info.icon = launcher.getPackageManager().getDefaultActivityIcon();
|
||||
info.icon = context.getPackageManager().getDefaultActivityIcon();
|
||||
info.customIcon = false;
|
||||
break;
|
||||
}
|
||||
@@ -1325,6 +1325,26 @@ public class LauncherModel {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item to the database in a specified container. Sets the container, screen, cellX and
|
||||
* cellY fields of the item. Also assigns an ID to the item.
|
||||
*/
|
||||
static boolean addGestureToDatabase(Context context, ItemInfo item, boolean notify) {
|
||||
final ContentValues values = new ContentValues();
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
|
||||
item.onAddToDatabase(values);
|
||||
|
||||
Uri result = cr.insert(notify ? LauncherSettings.Gestures.CONTENT_URI :
|
||||
LauncherSettings.Gestures.CONTENT_URI_NO_NOTIFICATION, values);
|
||||
|
||||
if (result != null) {
|
||||
item.id = Integer.parseInt(result.getPathSegments().get(1));
|
||||
}
|
||||
|
||||
return result != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an item to the database in a specified container.
|
||||
*/
|
||||
@@ -1359,4 +1379,84 @@ public class LauncherModel {
|
||||
cr.delete(LauncherSettings.Favorites.CONTENT_URI,
|
||||
LauncherSettings.Favorites.CONTAINER + "=" + info.id, null);
|
||||
}
|
||||
|
||||
static void deleteGestureFromDatabase(Context context, ItemInfo item) {
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
|
||||
cr.delete(LauncherSettings.Gestures.getContentUri(item.id, false), null, null);
|
||||
}
|
||||
|
||||
static void updateGestureInDatabase(Context context, ItemInfo item) {
|
||||
final ContentValues values = new ContentValues();
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
|
||||
item.onAddToDatabase(values);
|
||||
|
||||
cr.update(LauncherSettings.Gestures.getContentUri(item.id, false), values, null, null);
|
||||
}
|
||||
|
||||
|
||||
ApplicationInfo queryGesture(Context context, String id) {
|
||||
final ContentResolver contentResolver = context.getContentResolver();
|
||||
final PackageManager manager = context.getPackageManager();
|
||||
final Cursor c = contentResolver.query(
|
||||
LauncherSettings.Gestures.CONTENT_URI, null, LauncherSettings.Gestures._ID + "=?",
|
||||
new String[] { id }, null);
|
||||
|
||||
ApplicationInfo info = null;
|
||||
|
||||
try {
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures._ID);
|
||||
final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.INTENT);
|
||||
final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.TITLE);
|
||||
final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_TYPE);
|
||||
final int iconIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON);
|
||||
final int iconPackageIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_PACKAGE);
|
||||
final int iconResourceIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ICON_RESOURCE);
|
||||
final int itemTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Gestures.ITEM_TYPE);
|
||||
|
||||
String intentDescription;
|
||||
Intent intent;
|
||||
|
||||
if (c.moveToNext()) {
|
||||
int itemType = c.getInt(itemTypeIndex);
|
||||
|
||||
switch (itemType) {
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_APPLICATION:
|
||||
case LauncherSettings.Favorites.ITEM_TYPE_SHORTCUT:
|
||||
intentDescription = c.getString(intentIndex);
|
||||
try {
|
||||
intent = Intent.getIntent(intentDescription);
|
||||
} catch (java.net.URISyntaxException e) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (itemType == LauncherSettings.Favorites.ITEM_TYPE_APPLICATION) {
|
||||
info = getApplicationInfo(manager, intent, context);
|
||||
} else {
|
||||
info = getApplicationInfoShortcut(c, context, iconTypeIndex,
|
||||
iconPackageIndex, iconResourceIndex, iconIndex);
|
||||
}
|
||||
|
||||
if (info == null) {
|
||||
info = new ApplicationInfo();
|
||||
info.icon = manager.getDefaultActivityIcon();
|
||||
}
|
||||
|
||||
info.isGesture = true;
|
||||
info.title = c.getString(titleIndex);
|
||||
info.intent = intent;
|
||||
info.id = c.getLong(idIndex);
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
w(LOG_TAG, "Could not load gesture with name " + id);
|
||||
} finally {
|
||||
c.close();
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
|
||||
private static final String DATABASE_NAME = "launcher.db";
|
||||
|
||||
private static final int DATABASE_VERSION = 3;
|
||||
private static final int DATABASE_VERSION = 4;
|
||||
|
||||
static final String AUTHORITY = "com.android.launcher.settings";
|
||||
|
||||
@@ -63,10 +63,11 @@ public class LauncherProvider extends ContentProvider {
|
||||
static final String EXTRA_BIND_TARGETS = "com.android.launcher.settings.bindtargets";
|
||||
|
||||
static final String TABLE_FAVORITES = "favorites";
|
||||
static final String TABLE_GESTURES = "gestures";
|
||||
static final String PARAMETER_NOTIFY = "notify";
|
||||
|
||||
/**
|
||||
* {@link Uri} triggered at any registered {@link ContentObserver} when
|
||||
* {@link Uri} triggered at any registered {@link android.database.ContentObserver} when
|
||||
* {@link AppWidgetHost#deleteHost()} is called during database creation.
|
||||
* Use this to recall {@link AppWidgetHost#startListening()} if needed.
|
||||
*/
|
||||
@@ -99,7 +100,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
SQLiteQueryBuilder qb = new SQLiteQueryBuilder();
|
||||
qb.setTables(args.table);
|
||||
|
||||
SQLiteDatabase db = mOpenHelper.getReadableDatabase();
|
||||
SQLiteDatabase db = mOpenHelper.getWritableDatabase();
|
||||
Cursor result = qb.query(db, projection, args.where, args.args, null, null, sortOrder);
|
||||
result.setNotificationUri(getContext().getContentResolver(), uri);
|
||||
|
||||
@@ -220,6 +221,17 @@ public class LauncherProvider extends ContentProvider {
|
||||
"displayMode INTEGER" +
|
||||
");");
|
||||
|
||||
db.execSQL("CREATE TABLE gestures (" +
|
||||
"_id INTEGER PRIMARY KEY," +
|
||||
"title TEXT," +
|
||||
"intent TEXT," +
|
||||
"itemType INTEGER," +
|
||||
"iconType INTEGER," +
|
||||
"iconPackage TEXT," +
|
||||
"iconResource TEXT," +
|
||||
"icon BLOB" +
|
||||
");");
|
||||
|
||||
// Database was just created, so wipe any previous widgets
|
||||
if (mAppWidgetHost != null) {
|
||||
mAppWidgetHost.deleteHost();
|
||||
@@ -270,7 +282,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
}
|
||||
|
||||
private int copyFromCursor(SQLiteDatabase db, Cursor c) {
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ID);
|
||||
final int idIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites._ID);
|
||||
final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
|
||||
final int titleIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.TITLE);
|
||||
final int iconTypeIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.ICON_TYPE);
|
||||
@@ -289,7 +301,7 @@ public class LauncherProvider extends ContentProvider {
|
||||
int i = 0;
|
||||
while (c.moveToNext()) {
|
||||
ContentValues values = new ContentValues(c.getColumnCount());
|
||||
values.put(LauncherSettings.Favorites.ID, c.getLong(idIndex));
|
||||
values.put(LauncherSettings.Favorites._ID, c.getLong(idIndex));
|
||||
values.put(LauncherSettings.Favorites.INTENT, c.getString(intentIndex));
|
||||
values.put(LauncherSettings.Favorites.TITLE, c.getString(titleIndex));
|
||||
values.put(LauncherSettings.Favorites.ICON_TYPE, c.getInt(iconTypeIndex));
|
||||
@@ -352,6 +364,29 @@ public class LauncherProvider extends ContentProvider {
|
||||
convertWidgets(db);
|
||||
}
|
||||
}
|
||||
|
||||
if (version < 4) {
|
||||
db.beginTransaction();
|
||||
try {
|
||||
db.execSQL("CREATE TABLE gestures (" +
|
||||
"_id INTEGER PRIMARY KEY," +
|
||||
"title TEXT," +
|
||||
"intent TEXT," +
|
||||
"itemType INTEGER," +
|
||||
"iconType INTEGER," +
|
||||
"iconPackage TEXT," +
|
||||
"iconResource TEXT," +
|
||||
"icon BLOB" +
|
||||
");");
|
||||
db.setTransactionSuccessful();
|
||||
version = 4;
|
||||
} catch (SQLException ex) {
|
||||
// Old version remains, which means we wipe old data
|
||||
Log.e(LOG_TAG, ex.getMessage(), ex);
|
||||
} finally {
|
||||
db.endTransaction();
|
||||
}
|
||||
}
|
||||
|
||||
if (version != DATABASE_VERSION) {
|
||||
Log.w(LOG_TAG, "Destroying all old data.");
|
||||
|
||||
@@ -23,11 +23,109 @@ import android.net.Uri;
|
||||
* Settings related utilities.
|
||||
*/
|
||||
class LauncherSettings {
|
||||
static interface BaseLauncherColumns extends BaseColumns {
|
||||
/**
|
||||
* Descriptive name of the gesture that can be displayed to the user.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String TITLE = "title";
|
||||
|
||||
/**
|
||||
* The Intent URL of the gesture, describing what it points to. This
|
||||
* value is given to {@link android.content.Intent#getIntent} to create
|
||||
* an Intent that can be launched.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String INTENT = "intent";
|
||||
|
||||
/**
|
||||
* The type of the gesture
|
||||
*
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
static final String ITEM_TYPE = "itemType";
|
||||
|
||||
/**
|
||||
* The gesture is an application
|
||||
*/
|
||||
static final int ITEM_TYPE_APPLICATION = 0;
|
||||
|
||||
/**
|
||||
* The gesture is an application created shortcut
|
||||
*/
|
||||
static final int ITEM_TYPE_SHORTCUT = 1;
|
||||
|
||||
/**
|
||||
* The icon type.
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
static final String ICON_TYPE = "iconType";
|
||||
|
||||
/**
|
||||
* The icon is a resource identified by a package name and an integer id.
|
||||
*/
|
||||
static final int ICON_TYPE_RESOURCE = 0;
|
||||
|
||||
/**
|
||||
* The icon is a bitmap.
|
||||
*/
|
||||
static final int ICON_TYPE_BITMAP = 1;
|
||||
|
||||
/**
|
||||
* The icon package name, if icon type is ICON_TYPE_RESOURCE.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String ICON_PACKAGE = "iconPackage";
|
||||
|
||||
/**
|
||||
* The icon resource id, if icon type is ICON_TYPE_RESOURCE.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String ICON_RESOURCE = "iconResource";
|
||||
|
||||
/**
|
||||
* The custom icon bitmap, if icon type is ICON_TYPE_BITMAP.
|
||||
* <P>Type: BLOB</P>
|
||||
*/
|
||||
static final String ICON = "icon";
|
||||
}
|
||||
|
||||
static final class Gestures implements BaseLauncherColumns {
|
||||
/**
|
||||
* The content:// style URL for this table
|
||||
*/
|
||||
static final Uri CONTENT_URI = Uri.parse("content://" +
|
||||
LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_GESTURES +
|
||||
"?" + LauncherProvider.PARAMETER_NOTIFY + "=true");
|
||||
|
||||
/**
|
||||
* The content:// style URL for this table. When this Uri is used, no notification is
|
||||
* sent if the content changes.
|
||||
*/
|
||||
static final Uri CONTENT_URI_NO_NOTIFICATION = Uri.parse("content://" +
|
||||
LauncherProvider.AUTHORITY + "/" + LauncherProvider.TABLE_GESTURES +
|
||||
"?" + LauncherProvider.PARAMETER_NOTIFY + "=false");
|
||||
|
||||
/**
|
||||
* The content:// style URL for a given row, identified by its id.
|
||||
*
|
||||
* @param id The row id.
|
||||
* @param notify True to send a notification is the content changes.
|
||||
*
|
||||
* @return The unique content URL for the specified row.
|
||||
*/
|
||||
static Uri getContentUri(long id, boolean notify) {
|
||||
return Uri.parse("content://" + LauncherProvider.AUTHORITY +
|
||||
"/" + LauncherProvider.TABLE_GESTURES + "/" + id + "?" +
|
||||
LauncherProvider.PARAMETER_NOTIFY + "=" + notify);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Favorites. When changing these values, be sure to update
|
||||
* {@link com.android.settings.LauncherAppWidgetBinder} as needed.
|
||||
*/
|
||||
static final class Favorites implements BaseColumns {
|
||||
static final class Favorites implements BaseLauncherColumns {
|
||||
/**
|
||||
* The content:// style URL for this table
|
||||
*/
|
||||
@@ -57,26 +155,6 @@ class LauncherSettings {
|
||||
LauncherProvider.PARAMETER_NOTIFY + "=" + notify);
|
||||
}
|
||||
|
||||
/**
|
||||
* The row ID.
|
||||
* <p>Type: INTEGER</p>
|
||||
*/
|
||||
static final String ID = "_id";
|
||||
|
||||
/**
|
||||
* Descriptive name of the favorite that can be displayed to the user.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String TITLE = "title";
|
||||
|
||||
/**
|
||||
* The Intent URL of the favorite, describing what it points to. This
|
||||
* value is given to {@link android.content.Intent#getIntent} to create
|
||||
* an Intent that can be launched.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String INTENT = "intent";
|
||||
|
||||
/**
|
||||
* The container holding the favorite
|
||||
* <P>Type: INTEGER</P>
|
||||
@@ -120,23 +198,6 @@ class LauncherSettings {
|
||||
*/
|
||||
static final String SPANY = "spanY";
|
||||
|
||||
/**
|
||||
* The type of the favorite
|
||||
*
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
static final String ITEM_TYPE = "itemType";
|
||||
|
||||
/**
|
||||
* The favorite is an application
|
||||
*/
|
||||
static final int ITEM_TYPE_APPLICATION = 0;
|
||||
|
||||
/**
|
||||
* The favorite is an application created shortcut
|
||||
*/
|
||||
static final int ITEM_TYPE_SHORTCUT = 1;
|
||||
|
||||
/**
|
||||
* The favorite is a user created folder
|
||||
*/
|
||||
@@ -180,42 +241,9 @@ class LauncherSettings {
|
||||
* value is 1, it is an application-created shortcut.
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
@Deprecated
|
||||
static final String IS_SHORTCUT = "isShortcut";
|
||||
|
||||
/**
|
||||
* The icon type.
|
||||
* <P>Type: INTEGER</P>
|
||||
*/
|
||||
static final String ICON_TYPE = "iconType";
|
||||
|
||||
/**
|
||||
* The icon is a resource identified by a package name and an integer id.
|
||||
*/
|
||||
static final int ICON_TYPE_RESOURCE = 0;
|
||||
|
||||
/**
|
||||
* The icon is a bitmap.
|
||||
*/
|
||||
static final int ICON_TYPE_BITMAP = 1;
|
||||
|
||||
/**
|
||||
* The icon package name, if icon type is ICON_TYPE_RESOURCE.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String ICON_PACKAGE = "iconPackage";
|
||||
|
||||
/**
|
||||
* The icon resource id, if icon type is ICON_TYPE_RESOURCE.
|
||||
* <P>Type: TEXT</P>
|
||||
*/
|
||||
static final String ICON_RESOURCE = "iconResource";
|
||||
|
||||
/**
|
||||
* The custom icon bitmap, if icon type is ICON_TYPE_BITMAP.
|
||||
* <P>Type: BLOB</P>
|
||||
*/
|
||||
static final String ICON = "icon";
|
||||
|
||||
/**
|
||||
* The URI associated with the favorite. It is used, for instance, by
|
||||
* live folders to find the content provider.
|
||||
|
||||
@@ -35,7 +35,7 @@ public class UninstallShortcutReceiver extends BroadcastReceiver {
|
||||
if (intent != null && name != null) {
|
||||
final ContentResolver cr = context.getContentResolver();
|
||||
Cursor c = cr.query(LauncherSettings.Favorites.CONTENT_URI,
|
||||
new String[] { LauncherSettings.Favorites.ID, LauncherSettings.Favorites.INTENT },
|
||||
new String[] { LauncherSettings.Favorites._ID, LauncherSettings.Favorites.INTENT },
|
||||
LauncherSettings.Favorites.TITLE + "=?", new String[] { name }, null);
|
||||
|
||||
final int intentIndex = c.getColumnIndexOrThrow(LauncherSettings.Favorites.INTENT);
|
||||
|
||||