| /* |
| * 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; |
| } |
| } |
| } |